Home | History | Annotate | Download | only in id-auth
      1 page.title=Creating a Custom Account Type
      2 parent.title=Remembering and Authenticating Users
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 previous.title=Authenticating to OAuth2 Services
      7 previous.link=authenticate.html
      8 
      9 @jd:body
     10 
     11 <div id="tb-wrapper">
     12   <div id="tb">
     13 <h2>This lesson teaches you to</h2>
     14 <ol>
     15   <li><a href="#AccountCode">Implement Your Custom Account Code</a></li>
     16   <li><a href="#Security">Be Smart About Security!</a></li>
     17   <li><a href="#ExtendThatThing">Extend AbstractAccountAuthenticator</a></li>
     18   <li><a href="#TaskFour">Create an Authenticator Service</a></li>
     19   <li><a href="#DistributeService">Distribute Your Service</a></li>
     20 </ol>
     21 
     22 <h2>You should also read</h2>
     23 <ul>
     24   <li><a
     25 href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
     26 SampleSyncAdapter app</a></li>
     27 </ul>
     28   </div>
     29 </div>
     30 
     31 <p>So far we've talked about accessing Google APIs, which use accounts and users
     32 defined by Google. If you have your own online service, though, it won't have
     33 Google accounts or users, so what do you do? It turns out
     34 to be relatively straightforward to install new account types on a user's
     35 device. This lesson explains how to create a custom account type that works the
     36 same way as the built-in accounts do. </p>
     37 
     38 
     39 <h2 id="AccountCode">Implement Your Custom Account Code</h2>
     40 
     41 <p>The first thing you'll need is a way to get credentials from the user. This
     42 may be as simple as a dialog box that asks for a name and a password. Or it may
     43 be a more exotic procedure like a one-time password or a biometric scan. Either
     44 way, it's your responsibility to implement the code that:</p>
     45 <ol>
     46   <li>Collects credentials from the user</li>
     47   <li>Authenticates the credentials with the server</li>
     48   <li>Stores the credentials on the device</li>
     49 </ol>
     50 
     51 
     52 <p>Typically all three of these requirements can be handled by one activity. We'll call this the
     53 authenticator activity.</p>
     54 
     55 <p>Because they need to interact with the {@link android.accounts.AccountManager} system,
     56 authenticator activities have certain requirements that normal activities don't. To make it easy to
     57 get things right, the Android framework supplies a base class, {@link
     58 android.accounts.AccountAuthenticatorActivity}, which you can extend to create your own custom
     59 authenticator.</p>
     60 
     61 <p>How you address the first two requirements of an authenticator activity,
     62 credential collection and authentication, is completely up to you. (If there
     63 were only one way to do it, there'd be no need for "custom" account types, after
     64 all.) The third requirement has a canonical, and rather simple,
     65 implementation:</p>
     66 
     67 <pre>
     68 final Account account = new Account(mUsername, <em>your_account_type</em>);
     69 mAccountManager.addAccountExplicitly(account, mPassword, null);
     70 </pre>
     71 
     72 
     73 <h2 id="Security">Be Smart About Security!</h2>
     74 
     75 <p>It's important to understand that {@link android.accounts.AccountManager} is not an encryption
     76 service
     77 or a keychain. It stores account credentials just as you pass them, in <strong>plain
     78 text</strong>. On most devices, this isn't
     79 a particular concern, because it stores them in
     80 a database that is only accessible to root. But on a rooted device, the
     81 credentials would be readable by anyone with {@code adb} access to the device.</p>
     82 
     83 <p>With this in mind, you shouldn't pass the user's actual
     84 password to {@link android.accounts.AccountManager#addAccountExplicitly 
     85 AccountManager.addAccountExplicitly()}. Instead, you should store a
     86 cryptographically secure token that would be of limited use to an attacker. If your
     87 user credentials are protecting something valuable, you should carefully
     88 consider doing something similar.</p>
     89 
     90 <p class="caution"><strong>Remember:</strong> When it comes to security code, follow the
     91 "Mythbusters" rule: don't try this at home! Consult a security professional before implementing any
     92 custom account code.</p>
     93 
     94 <p>Now that the security disclaimers are out of the way, it's time to get back to work.
     95 You've already implemented the meat of your custom account code; what's left is
     96 plumbing.</p>
     97 
     98 
     99 <h2 id="ExtendThatThing">Extend AbstractAccountAuthenticator</h2>
    100 
    101 <p>In order for the {@link android.accounts.AccountManager} to work with your custom account
    102 code, you
    103 need a class that implements the interfaces that {@link android.accounts.AccountManager} expects.
    104 This class is the <em>authenticator class</em>.</p>
    105 
    106 <p>The easiest way to create an authenticator class is to extend
    107 {@link android.accounts.AbstractAccountAuthenticator} and implement its abstract methods. If you've
    108 worked through the previous lessons, the abstract methods of
    109 {@link android.accounts.AbstractAccountAuthenticator} should look familiar: they're the opposite
    110 side of
    111 the methods you called in the previous lesson to get account information and
    112 authorization tokens.</p>
    113 
    114 <p>Implementing an authenticator class properly requires a number of separate
    115 pieces of code. First, {@link android.accounts.AbstractAccountAuthenticator} has seven abstract
    116 methods that you must override. Second, you need to add an
    117 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filter</a> for
    118 <code>"android.accounts.AccountAuthenticator"</code> to your application
    119 manifest (shown in the next section). Finally, you must supply two XML resources that define, among
    120 other
    121 things, the name of your custom account type and the icon that the system will
    122 display next to accounts of this type.</p>
    123 
    124 <p> You can find a step-by-step guide to implementing a successful authenticator class and the XML
    125 files in the {@link android.accounts.AbstractAccountAuthenticator} documentation. There's also a
    126 sample implementation in the <a
    127 href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
    128 SampleSyncAdapter sample app</a>.</p>
    129 
    130 <p>As you read through the SampleSyncAdapter code, you'll notice that several of
    131 the methods return an intent in a bundle. This is the same intent that will be
    132 used to launch your custom authenticator activity. If your authenticator
    133 activity needs any special initialization parameters, you can attach them to the
    134 intent using {@link android.content.Intent#putExtra Intent.putExtra()}.</p>
    135 
    136 
    137 <h2 id="TaskFour">Create an Authenticator Service</h2>
    138 
    139 <p>Now that you have an authenticator class, you need a place for it to live.
    140 Account authenticators need to be available to multiple applications and work in
    141 the background, so naturally they're required to run inside a {@link android.app.Service}. We'll
    142 call this the authenticator service.</p>
    143 
    144 <p>Your authenticator service can be very simple. All it needs to do is create
    145 an instance of your authenticator class in {@link android.app.Service#onCreate onCreate()} and call
    146 {@link android.accounts.AbstractAccountAuthenticator#getIBinder getIBinder()} in {@link
    147 android.app.Service#onBind onBind()}. The <a
    148 href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
    149 SampleSyncAdapter</a> contains a good example of an authenticator service.</p>
    150 
    151 <p>Don't forget to add a {@code <service>} tag to your manifest file
    152 and add an intent filter for the AccountAuthenticator intent and declare the account
    153 authenticator:</p>
    154 
    155 <pre>
    156 &lt;service ...>
    157    &lt;intent-filter>
    158       &lt;action android:name="android.accounts.AccountAuthenticator" />
    159    &lt;/intent-filter>
    160    &lt;meta-data android:name="android.accounts.AccountAuthenticator"
    161              android:resource="@xml/authenticator" />
    162 &lt;/service>
    163 </pre>
    164 
    165 
    166 <h2 id="DistributeService">Distribute Your Service</h2>
    167 
    168 <p>You're done! The system now recognizes your account type, right alongside all
    169 the big name account types like "Google" and "Corporate." You can use the
    170 <strong>Accounts &amp; Sync</strong> Settings page to add an account, and apps that ask for
    171 accounts of your custom type will be able to enumerate and authenticate just as
    172 they would with any other account type.</p>
    173 
    174 <p>Of course, all of this assumes that your account service is actually
    175 installed on the device. If only one app will ever access the service, then
    176 this isn't a big deal&mdash;just bundle the service in the app.
    177 But if you want your account service to be used by more than one app, things get
    178 trickier. You don't want to bundle the service with all of your apps and have
    179 multiple copies of it taking up space on your user's device.</p>
    180 
    181 <p>One solution is to place the service in one small, special-purpose APK. When
    182 an app wishes to use your custom account type, it can check the device to see if
    183 your custom account service is available. If not, it can direct the user to
    184 Google Play to download the service. This may seem like a great deal of
    185 trouble at first, but compared with the alternative of re-entering credentials
    186 for every app that uses your custom account, it's refreshingly easy.</p>
    187