1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.volley.toolbox; 18 19 import com.android.volley.AuthFailureError; 20 21 import android.accounts.Account; 22 import android.accounts.AccountManager; 23 import android.accounts.AccountManagerFuture; 24 import android.annotation.SuppressLint; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.os.Bundle; 28 29 /** 30 * An Authenticator that uses {@link AccountManager} to get auth 31 * tokens of a specified type for a specified account. 32 */ 33 // TODO: Update this to account for runtime permissions 34 @SuppressLint("MissingPermission") 35 public class AndroidAuthenticator implements Authenticator { 36 private final AccountManager mAccountManager; 37 private final Account mAccount; 38 private final String mAuthTokenType; 39 private final boolean mNotifyAuthFailure; 40 41 /** 42 * Creates a new authenticator. 43 * @param context Context for accessing AccountManager 44 * @param account Account to authenticate as 45 * @param authTokenType Auth token type passed to AccountManager 46 */ 47 public AndroidAuthenticator(Context context, Account account, String authTokenType) { 48 this(context, account, authTokenType, false); 49 } 50 51 /** 52 * Creates a new authenticator. 53 * @param context Context for accessing AccountManager 54 * @param account Account to authenticate as 55 * @param authTokenType Auth token type passed to AccountManager 56 * @param notifyAuthFailure Whether to raise a notification upon auth failure 57 */ 58 public AndroidAuthenticator(Context context, Account account, String authTokenType, 59 boolean notifyAuthFailure) { 60 this(AccountManager.get(context), account, authTokenType, notifyAuthFailure); 61 } 62 63 // Visible for testing. Allows injection of a mock AccountManager. 64 AndroidAuthenticator(AccountManager accountManager, Account account, 65 String authTokenType, boolean notifyAuthFailure) { 66 mAccountManager = accountManager; 67 mAccount = account; 68 mAuthTokenType = authTokenType; 69 mNotifyAuthFailure = notifyAuthFailure; 70 } 71 72 /** 73 * Returns the Account being used by this authenticator. 74 */ 75 public Account getAccount() { 76 return mAccount; 77 } 78 79 /** 80 * Returns the Auth Token Type used by this authenticator. 81 */ 82 public String getAuthTokenType() { 83 return mAuthTokenType; 84 } 85 86 // TODO: Figure out what to do about notifyAuthFailure 87 @SuppressWarnings("deprecation") 88 @Override 89 public String getAuthToken() throws AuthFailureError { 90 AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount, 91 mAuthTokenType, mNotifyAuthFailure, null, null); 92 Bundle result; 93 try { 94 result = future.getResult(); 95 } catch (Exception e) { 96 throw new AuthFailureError("Error while retrieving auth token", e); 97 } 98 String authToken = null; 99 if (future.isDone() && !future.isCancelled()) { 100 if (result.containsKey(AccountManager.KEY_INTENT)) { 101 Intent intent = result.getParcelable(AccountManager.KEY_INTENT); 102 throw new AuthFailureError(intent); 103 } 104 authToken = result.getString(AccountManager.KEY_AUTHTOKEN); 105 } 106 if (authToken == null) { 107 throw new AuthFailureError("Got null auth token for type: " + mAuthTokenType); 108 } 109 110 return authToken; 111 } 112 113 @Override 114 public void invalidateAuthToken(String authToken) { 115 mAccountManager.invalidateAuthToken(mAccount.type, authToken); 116 } 117 } 118