1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.example.android.samplesync.authenticator; 18 19import com.example.android.samplesync.Constants; 20import com.example.android.samplesync.client.NetworkUtilities; 21 22import android.accounts.AbstractAccountAuthenticator; 23import android.accounts.Account; 24import android.accounts.AccountAuthenticatorResponse; 25import android.accounts.AccountManager; 26import android.accounts.NetworkErrorException; 27import android.content.Context; 28import android.content.Intent; 29import android.os.Bundle; 30import android.text.TextUtils; 31import android.util.Log; 32 33/** 34 * This class is an implementation of AbstractAccountAuthenticator for 35 * authenticating accounts in the com.example.android.samplesync domain. The 36 * interesting thing that this class demonstrates is the use of authTokens as 37 * part of the authentication process. In the account setup UI, the user enters 38 * their username and password. But for our subsequent calls off to the service 39 * for syncing, we want to use an authtoken instead - so we're not continually 40 * sending the password over the wire. getAuthToken() will be called when 41 * SyncAdapter calls AccountManager.blockingGetAuthToken(). When we get called, 42 * we need to return the appropriate authToken for the specified account. If we 43 * already have an authToken stored in the account, we return that authToken. If 44 * we don't, but we do have a username and password, then we'll attempt to talk 45 * to the sample service to fetch an authToken. If that fails (or we didn't have 46 * a username/password), then we need to prompt the user - so we create an 47 * AuthenticatorActivity intent and return that. That will display the dialog 48 * that prompts the user for their login information. 49 */ 50class Authenticator extends AbstractAccountAuthenticator { 51 52 /** The tag used to log to adb console. **/ 53 private static final String TAG = "Authenticator"; 54 55 // Authentication Service context 56 private final Context mContext; 57 58 public Authenticator(Context context) { 59 super(context); 60 mContext = context; 61 } 62 63 @Override 64 public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, 65 String authTokenType, String[] requiredFeatures, Bundle options) { 66 Log.v(TAG, "addAccount()"); 67 final Intent intent = new Intent(mContext, AuthenticatorActivity.class); 68 intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); 69 final Bundle bundle = new Bundle(); 70 bundle.putParcelable(AccountManager.KEY_INTENT, intent); 71 return bundle; 72 } 73 74 @Override 75 public Bundle confirmCredentials( 76 AccountAuthenticatorResponse response, Account account, Bundle options) { 77 Log.v(TAG, "confirmCredentials()"); 78 return null; 79 } 80 81 @Override 82 public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { 83 Log.v(TAG, "editProperties()"); 84 throw new UnsupportedOperationException(); 85 } 86 87 @Override 88 public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, 89 String authTokenType, Bundle loginOptions) throws NetworkErrorException { 90 Log.v(TAG, "getAuthToken()"); 91 92 // If the caller requested an authToken type we don't support, then 93 // return an error 94 if (!authTokenType.equals(Constants.AUTHTOKEN_TYPE)) { 95 final Bundle result = new Bundle(); 96 result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType"); 97 return result; 98 } 99 100 // Extract the username and password from the Account Manager, and ask 101 // the server for an appropriate AuthToken. 102 final AccountManager am = AccountManager.get(mContext); 103 final String password = am.getPassword(account); 104 if (password != null) { 105 final String authToken = NetworkUtilities.authenticate(account.name, password); 106 if (!TextUtils.isEmpty(authToken)) { 107 final Bundle result = new Bundle(); 108 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 109 result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); 110 result.putString(AccountManager.KEY_AUTHTOKEN, authToken); 111 return result; 112 } 113 } 114 115 // If we get here, then we couldn't access the user's password - so we 116 // need to re-prompt them for their credentials. We do that by creating 117 // an intent to display our AuthenticatorActivity panel. 118 final Intent intent = new Intent(mContext, AuthenticatorActivity.class); 119 intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); 120 intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType); 121 intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); 122 final Bundle bundle = new Bundle(); 123 bundle.putParcelable(AccountManager.KEY_INTENT, intent); 124 return bundle; 125 } 126 127 @Override 128 public String getAuthTokenLabel(String authTokenType) { 129 // null means we don't support multiple authToken types 130 Log.v(TAG, "getAuthTokenLabel()"); 131 return null; 132 } 133 134 @Override 135 public Bundle hasFeatures( 136 AccountAuthenticatorResponse response, Account account, String[] features) { 137 // This call is used to query whether the Authenticator supports 138 // specific features. We don't expect to get called, so we always 139 // return false (no) for any queries. 140 Log.v(TAG, "hasFeatures()"); 141 final Bundle result = new Bundle(); 142 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); 143 return result; 144 } 145 146 @Override 147 public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, 148 String authTokenType, Bundle loginOptions) { 149 Log.v(TAG, "updateCredentials()"); 150 return null; 151 } 152} 153