package com.seafile.seadroid2.account; import android.accounts.*; import android.accounts.AccountManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.ui.SeafileAuthenticatorActivity; import com.seafile.seadroid2.data.DataManager; import org.json.JSONException; import java.net.HttpURLConnection; /* * Seafile Authenticator. * */ public class Authenticator extends AbstractAccountAuthenticator { private String DEBUG_TAG = "SeafileAuthenticator"; private final Context context; private com.seafile.seadroid2.account.AccountManager manager; /** * Type of the auth token used (there is only one type) */ public static final String AUTHTOKEN_TYPE = "api2"; /** * Key of Server URI in userData */ public final static String KEY_SERVER_URI = "server"; /** * Key of email in userData */ public final static String KEY_EMAIL = "email"; /** * Key of Server version in userData */ public final static String KEY_SERVER_VERSION = "version"; /** * Key of Server Feature-list in userData */ public final static String KEY_SERVER_FEATURES = "features"; /** * Key of shib_setting in userData */ public final static String KEY_SHIB = "shib"; public Authenticator(Context context) { super(context); Log.d(DEBUG_TAG, "SeafileAuthenticator created."); this.context = context; this.manager = new com.seafile.seadroid2.account.AccountManager(context); } /** * We have no properties. */ @Override public Bundle editProperties( AccountAuthenticatorResponse r, String s) { Log.d(DEBUG_TAG, "editProperties"); throw new UnsupportedOperationException(); } @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { Log.d(DEBUG_TAG, "addAccount of type "+accountType); if (authTokenType != null && !authTokenType.equals(Authenticator.AUTHTOKEN_TYPE)) { Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_ARGUMENTS); return result; } final Intent intent = new Intent(context, SeafileAuthenticatorActivity.class); intent.putExtra(SeafileAuthenticatorActivity.ARG_ACCOUNT_TYPE, accountType); intent.putExtra(SeafileAuthenticatorActivity.ARG_IS_EDITING, false); intent.putExtra(android.accounts.AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(android.accounts.AccountManager.KEY_INTENT, intent); return bundle; } @Override public Bundle confirmCredentials( AccountAuthenticatorResponse response, android.accounts.Account account, Bundle bundle) throws NetworkErrorException { Log.d(DEBUG_TAG, "confirmCredentials"); Account a = manager.getSeafileAccount(account); DataManager manager = new DataManager(a); try { // test auth token manager.getAccountInfo(); } catch (SeafException e) { if (e.getCode() == HttpURLConnection.HTTP_UNAUTHORIZED) { // Token is invalid Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE); result.putString(AccountManager.KEY_ERROR_MESSAGE, "Authentication error."); return result; } else { // could not test token throw new NetworkErrorException(e); } } catch (JSONException e) { throw new NetworkErrorException(e); } // token is valid Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); return result; } @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, android.accounts.Account account, String authTokenType, Bundle options) throws NetworkErrorException { Log.d(DEBUG_TAG, "getAuthToken"); if (authTokenType != null && !authTokenType.equals(Authenticator.AUTHTOKEN_TYPE)) { final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_ARGUMENTS); return result; } final AccountManager am = AccountManager.get(context); String authToken = am.peekAuthToken(account, authTokenType); 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; } // there is no auth token -> the account is signed-out. final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_REQUEST); result.putString(android.accounts.AccountManager.KEY_ERROR_MESSAGE, "Account is not signed in. Not auth token available."); return result; } @Override public String getAuthTokenLabel(String authTokenType) { return "Seafile"; } @Override public Bundle updateCredentials(AccountAuthenticatorResponse response, android.accounts.Account account, String authTokenType, Bundle options) throws NetworkErrorException { Log.d(DEBUG_TAG, "updateCredentials"); if (authTokenType != null && !authTokenType.equals(Authenticator.AUTHTOKEN_TYPE)) { final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_ARGUMENTS); return result; } final Intent intent = new Intent(context, SeafileAuthenticatorActivity.class); intent.putExtra(android.accounts.AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); intent.putExtra(SeafileAuthenticatorActivity.ARG_ACCOUNT_TYPE, account.type); intent.putExtra(SeafileAuthenticatorActivity.ARG_ACCOUNT_NAME, account.name); // will be overridden intent.putExtra(SeafileAuthenticatorActivity.ARG_EDIT_OLD_ACCOUNT_NAME, account.name); intent.putExtra(SeafileAuthenticatorActivity.ARG_IS_EDITING, true); boolean is_shib = manager.getSeafileAccount(account).isShib(); intent.putExtra(SeafileAuthenticatorActivity.ARG_SHIB, is_shib); final Bundle bundle = new Bundle(); bundle.putParcelable(android.accounts.AccountManager.KEY_INTENT, intent); return bundle; } @Override public Bundle hasFeatures(AccountAuthenticatorResponse r, android.accounts.Account account, String[] strings) throws NetworkErrorException { Log.d(DEBUG_TAG, "hasFeatures"); final Bundle result = new Bundle(); result.putBoolean(android.accounts.AccountManager.KEY_BOOLEAN_RESULT, true); return result; } }