AbstractAccountAuthenticator.java revision ffd0cb04f97e62d286d185c520580d81a9c328b1
1/*
2 * Copyright (C) 2009 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
17package android.accounts;
18
19import android.os.Bundle;
20import android.os.RemoteException;
21import android.os.Binder;
22import android.util.Log;
23import android.content.pm.PackageManager;
24import android.content.Context;
25import android.Manifest;
26
27/**
28 * Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator
29 * binder interface and also provides helper libraries to simplify the creation of
30 * AccountAuthenticators.
31 */
32public abstract class AbstractAccountAuthenticator {
33    private final Context mContext;
34
35    public AbstractAccountAuthenticator(Context context) {
36        mContext = context;
37    }
38
39    class Transport extends IAccountAuthenticator.Stub {
40        public void addAccount(IAccountAuthenticatorResponse response, String accountType,
41                String authTokenType, String[] requiredFeatures, Bundle options)
42                throws RemoteException {
43            checkBinderPermission();
44            final Bundle result;
45            try {
46                result = AbstractAccountAuthenticator.this.addAccount(
47                    new AccountAuthenticatorResponse(response),
48                        accountType, authTokenType, requiredFeatures, options);
49            } catch (NetworkErrorException e) {
50                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
51                return;
52            } catch (UnsupportedOperationException e) {
53                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
54                        "addAccount not supported");
55                return;
56            }
57            if (result != null) {
58                response.onResult(result);
59            }
60        }
61
62        public void confirmPassword(IAccountAuthenticatorResponse response,
63                Account account, String password) throws RemoteException {
64            checkBinderPermission();
65            boolean result;
66            try {
67                result = AbstractAccountAuthenticator.this.confirmPassword(
68                    new AccountAuthenticatorResponse(response),
69                        account, password);
70            } catch (UnsupportedOperationException e) {
71                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
72                        "confirmPassword not supported");
73                return;
74            } catch (NetworkErrorException e) {
75                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
76                return;
77            }
78            Bundle bundle = new Bundle();
79            bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result);
80            response.onResult(bundle);
81        }
82
83        public void confirmCredentials(IAccountAuthenticatorResponse response,
84                Account account) throws RemoteException {
85            checkBinderPermission();
86            final Bundle result;
87            try {
88                result = AbstractAccountAuthenticator.this.confirmCredentials(
89                    new AccountAuthenticatorResponse(response), account);
90            } catch (UnsupportedOperationException e) {
91                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
92                        "confirmCredentials not supported");
93                return;
94            }
95            if (result != null) {
96                response.onResult(result);
97            }
98        }
99
100        public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
101                String authTokenType)
102                throws RemoteException {
103            checkBinderPermission();
104            try {
105                Bundle result = new Bundle();
106                result.putString(Constants.AUTH_TOKEN_LABEL_KEY,
107                        AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
108                response.onResult(result);
109            } catch (IllegalArgumentException e) {
110                response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS,
111                        "unknown authTokenType");
112            } catch (UnsupportedOperationException e) {
113                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
114                        "getAuthTokenTypeLabel not supported");
115            }
116        }
117
118        public void getAuthToken(IAccountAuthenticatorResponse response,
119                Account account, String authTokenType, Bundle loginOptions)
120                throws RemoteException {
121            checkBinderPermission();
122            try {
123                final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
124                        new AccountAuthenticatorResponse(response), account,
125                        authTokenType, loginOptions);
126                if (result != null) {
127                    response.onResult(result);
128                }
129            } catch (UnsupportedOperationException e) {
130                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
131                        "getAuthToken not supported");
132            } catch (NetworkErrorException e) {
133                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
134            }
135        }
136
137        public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
138                String authTokenType, Bundle loginOptions) throws RemoteException {
139            checkBinderPermission();
140            final Bundle result;
141            try {
142                result = AbstractAccountAuthenticator.this.updateCredentials(
143                    new AccountAuthenticatorResponse(response), account,
144                        authTokenType, loginOptions);
145            } catch (UnsupportedOperationException e) {
146                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
147                        "updateCredentials not supported");
148                return;
149            }
150            if (result != null) {
151                response.onResult(result);
152            }
153        }
154
155        public void editProperties(IAccountAuthenticatorResponse response,
156                String accountType) throws RemoteException {
157            checkBinderPermission();
158            final Bundle result;
159            try {
160                result = AbstractAccountAuthenticator.this.editProperties(
161                    new AccountAuthenticatorResponse(response), accountType);
162            } catch (UnsupportedOperationException e) {
163                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
164                        "editProperties not supported");
165                return;
166            }
167            if (result != null) {
168                response.onResult(result);
169            }
170        }
171
172        public void hasFeatures(IAccountAuthenticatorResponse response,
173                Account account, String[] features) throws RemoteException {
174            checkBinderPermission();
175            final Bundle result;
176            try {
177                result = AbstractAccountAuthenticator.this.hasFeatures(
178                    new AccountAuthenticatorResponse(response), account, features);
179            } catch (UnsupportedOperationException e) {
180                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
181                        "hasFeatures not supported");
182                return;
183            } catch (NetworkErrorException e) {
184                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
185                return;
186            }
187            if (result != null) {
188                response.onResult(result);
189            }
190        }
191
192        public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
193                Account account) throws RemoteException {
194            checkBinderPermission();
195            try {
196                final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
197                    new AccountAuthenticatorResponse(response), account);
198                if (result != null) {
199                    response.onResult(result);
200                }
201            } catch (UnsupportedOperationException e) {
202                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
203                        "getAccountRemovalAllowed not supported");
204                return;
205            } catch (NetworkErrorException e) {
206                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
207                return;
208            }
209        }
210    }
211
212    private void checkBinderPermission() {
213        final int uid = Binder.getCallingUid();
214        final String perm = Manifest.permission.ACCOUNT_MANAGER_SERVICE;
215        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
216            throw new SecurityException("caller uid " + uid + " lacks " + perm);
217        }
218    }
219
220    Transport mTransport = new Transport();
221
222    /**
223     * @return the IAccountAuthenticator binder transport object
224     */
225    public final IAccountAuthenticator getIAccountAuthenticator()
226    {
227        return mTransport;
228    }
229
230    /**
231     * Returns a Bundle that contains the Intent of the activity that can be used to edit the
232     * properties. In order to indicate success the activity should call response.setResult()
233     * with a non-null Bundle.
234     * @param response used to set the result for the request. If the Constants.INTENT_KEY
235     *   is set in the bundle then this response field is to be used for sending future
236     *   results if and when the Intent is started.
237     * @param accountType the AccountType whose properties are to be edited.
238     * @return a Bundle containing the result or the Intent to start to continue the request.
239     *   If this is null then the request is considered to still be active and the result should
240     *   sent later using response.
241     */
242    public abstract Bundle editProperties(AccountAuthenticatorResponse response,
243            String accountType);
244    public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
245            String authTokenType, String[] requiredFeatures, Bundle options)
246            throws NetworkErrorException;
247    /* @deprecated */
248    public abstract boolean confirmPassword(AccountAuthenticatorResponse response,
249            Account account, String password) throws NetworkErrorException;
250    public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
251            Account account);
252    public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
253            Account account, String authTokenType, Bundle loginOptions)
254            throws NetworkErrorException;
255    public abstract String getAuthTokenLabel(String authTokenType);
256    public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
257            Account account, String authTokenType, Bundle loginOptions);
258    public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
259            Account account, String[] features) throws NetworkErrorException;
260    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
261            Account account) throws NetworkErrorException {
262        final Bundle result = new Bundle();
263        result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true);
264        return result;
265    }
266}
267