Kerberos for Chrome on Android

This is now implemented; see https://bugs.chromium.org/p/chromium/issues/detail?id=474943

Summary

The desktop versions of Chrome already support Kerberos authentication. A number of third parties have approached us, requesting that we add Kerberos support to Chrome for Android. This document describes how this can be done.

How does Kerberos authentication work in desktop Chrome?

Desktop versions of Chrome (excluding Chrome OS) support 4 HTTP authentication schemes (see https://www.chromium.org/developers/design-documents/http-authentication). One of these, the Negotiate scheme, implements SPNEGO authentication. SPNEGO tokens may wrap Kerberos tokens, so this provides Kerberos authentication.

On Posix systems (other than Android) SPNEGO is supported using a library implementing GSSAPI.

  • Chrome sends a GET request to the host.
  • The host returns an HTTP 401 error, containing a Authentication Negotiate header, and possibly a SPNEGO token.
  • Chrome derives the SPNEGO (Kerberos) principal from the URL, and passes this, together with any token received from the host, to the gssapi library. The gssapi library returns a new token.
  • Chrome sends a new GET request to the host, containing the new token.

This may repeat a number of times before a GET request finally succeeds or fails.

Unfortunately there is no single standard for Kerberos, but only for the GSSAPI, which is an API for libraries implementing Kerberos and similar authentication protocols. To solve this Chrome loads the gssapi library at run time, hence allowing users (actually typically corporate IT managers) to choose a version of Kerberos to use by installing a suitable gssapi library.

On Windows Chrome uses SSPI instead of GSSAPI, but the principles are similar.

Android account management

Android includes an Account management framework. The application interface to this is AccountManager, which provides various members to get accounts, and to get authentication tokens from accounts. Every account on a device has an “accountType” and may also have features (which are simple strings) describing its intended use.

The accounts are provided by account authenticators (see AbstractAccountAuthenticator). Any app may provide an account authenticator, and all account authenticators on a device are visible to all apps on the device. Each account authenticator provides a single accountType of account. The account authenticators provide functions for:

  • Adding and removing accounts
  • Setting and checking account credentials.
  • Getting authorization tokens from accounts.

Options for supporting Kerberos in Chrome for Android

The obvious way to support Kerberos on Android would be to follow the Posix strategy, and for system administrators to install GSSAPI libraries that Chrome would then search for. There are, however, a number of reasons why this might not be the best solution:

  • The library cannot be installed on the system directories, since users (including system administrators) and apps do not have, and cannot generally get, root access on Android.
  • As such, the library would have to be installed as part of a specialized Kerberos app. Chrome would need to know, or be told, how to find this.
  • The app GSSAPI library would have to support a UI for creating, authorizing, and managing Kerberos accounts. For this to fit well into Android this would have to use the Android account management framework, so the app would almost certainly need to implement an Android account authenticator.
  • Android, and Android developers, generally expect interfaces between apps to be Java interfaces using Intents. Since there is already a Java account management API, which includes authentication support, it seems undesirable to add a new authentication api to Android.

In view of these concerns, we should consider using the Android AccountManager to provide SPNEGO and hence Kerberos support on Android. In addition to avoiding the problems with installing and using a GSSAPI library on Android, this would have the advantage of making Kerberos authentication available to other Android apps.

The disadvantage is that it involves slightly more work in Chrome, and adding some Android specific Kerberos authentication code to Chrome, but this is probably worthwhile.

How should Kerberos on Android look to the user

The ideal would probably be:

  • The user, or, more likely, the work profile administrator, installs a Kerberos app on the phone.
  • The work profile administrator configures the Kerberos settings in the application (possibly by providing a krb5.conf file), and configures Chrome to use the Android account type provided by the app for SPNEGO (including Kerberos) Authentication.
  • Android ensures that only one app can provide accounts for each account type. If multiple apps attempt to provide accounts for the same account type then the first installed app wins. This means that new apps cannot intercept, or see, authentication requests for an existing account type.
  • The work profile administrator configures, in Chrome, a whitelist of sites that can use SPNEGO authentication.
  • The user signs into a Kerberos account, with a username and password, or other authentication mechanism as defined by the SPNEGO Authentication app.
  • The Kerberos account will correspond to a single Kerberos user principal.
  • When the user signs in the Kerberos app will, typically, use the user provided authentication data to fetch and store a TGT. It will not store the password.
  • TGTs have limited life; typically no more than a month, so, once the TGT expires, the user will have sign in again.
  • The user accesses a web site that requires Kerberos authentication:
  • If there is no SPNEGO Authentication app configured in Chrome then authentication fails.
  • If the site isn’t whitelisted for SPNEGO authentication then authentication fails.
  • If there are no signed in Kerberos accounts then either access is refused or the user is asked to add a Kerberos account (depending on the Kerberos app).
  • If there is precisely one Kerberos account then Chrome will attempt to use that account to authenticate the service principal.
  • The first time Chrome uses a particular Kerberos account for a particular service principal Android will ask the user for permission to use that account before attempting to authenticate the service principal.
  • If there are multiple Kerberos accounts then the user will be asked to select one to be used to authenticate the service principal.
  • Should Chrome remember the user’s choice? If so, should Chrome apply it to just that SPN, or to all SPNs? Under what circumstances should Chrome forget a previous choice?

SPNEGO Account Authenticators

SPNEGO account authenticators will be provided by third parties. They will support SPNEGO authentication initiation. They must define an account type with customTokens. This is needed because SPENGO authentication is incompatible with Android’s default auth token caching[1].

They must provide accounts with the following properties:

  • All SPNEGO accounts must have the feature “SPNEGO” (see AbstractAccountAuthenticator.hasFeatures()).
  • If the underlying authentication scheme for an account is Kerberos then the account shall support precisely one user principal.
  • For all SPNEGO accounts getAuthToken shalll accept authTokenType of “SPNEGO:HOSTBASED:<principal name>”
  • <principal name> is the host based principal name (“HOSTBASED” is included to allow for the possibility of future extension to other principal types).
  • If this is the second or later step in a multi-step authentication sequence, then the options bundle must include the incoming token and the SPNEGO context.
  • getAuthToken returns a Bundle (possibly indirectly through the AccountAuthenticatorResponse, see  getAuthToken). Unless authentication has failed then this bundle shall contain the returned token.
  • If authentication is incomplete then the returned bundle shall contain the the SPNEGO context for continuing authentication.
  • The formats to be used for tokens and contexts, and keys to identify them in the bundles, are still TBD.
  • SPNEGO encapsulation will be the responsibility of the SPNEGO Authenticator app, so all tokens passed between Chrome and the app will be SPNEGO encapsulated.
  • The Account type provided by Authenticator App should be unique to that Authenticator (e.g. “com.companyname.kerberos_authenticator” not simply “KerberosAuthenticator”) to avoid possible clashes with other Kerberos authenticators.

Implementation in Chrome

To implement this in Chrome we will define a new implementation of AuthSystem, as used by http_auth_handler_negotiate.h. The critical function of this interface is GenerateAuthToken. The implementation of this will largely be similar to the posix version (HttpAuthGSSAPI::GenerateAuthToken) however HttpAuthGSSAPI::GetNextSecurityToken

will be reimplemented to call a new Java function.

The Java function will

  • Get the Android Account Type from the Chrome preferences.
  • It might be easier to do this on the C++ side, but this is an implementation detail TBD.
  • Using this account type call GetAuthTokenByFeatures() with the service principal and any previous incoming token to get the (next) outgoing token.
  • If this is a new request the Android framework will show the user an Access Request dialog (which the user can reject) before granting it [[To be confirmed]].

Note:

  1. The current call to GenerateAuthToken (called on the IO thread) assumes that it will return a result synchronously. There is already a TODO in the code to allow it to return its result asynchronously. As part of this work we will change the interface to GenerateAuthToken to allow asynchronous return, and modify the calling code to support this. This is necessary because getting a token on Android may involve the user giving permission. The Android AccountManager functions all return their results asynchronously, in Futures, so can easily provide an asynchronous result.
  • We will not, at present, change the desktop implementations to return results asynchronously, but this could, and probably should, be done in future, since, even without the need for user interaction, getting a Kerberos token can involve network transactions.
  1. The code for verifying that the site is whitelisted for Kerberos authentication already exists, and will be unchanged by this. The only change will be to enable this, together with the other existing common Kerberos code, in Android builds.

Implementation of SPNEGO Account Authenticators

SPNEGO Account Authenticators will be provided by third parties, so the following are recommendations:

  • Each account provided by an SPNEGO Account Authenticator should correspond to a single user principal (account) provided by single key distribution center.
  • The account authenticator should not store any passwords. Instead it should store TGTs for the user principles, and require the users to re-enter their passwords (or other authentication data) when their TGT expires.
  • The account authenticator should keep a list of authorized applications (or application signatures) for each account, and refuse to provide service tokens to other applications. The list of authorized applications may be:
  • Built into the account authenticator.
  • Configurable by the system administrator
  • Configurable by the user. In this case the account authenticator might choose to allow the user to authorize new applications dynamically when they first request access..

The authenticator can get the uid of the calling app using the KEY_CALLER_UID field of the options bundle, and then identify the requesting application using context.getPackageManager().getNameForUid() or similar.

This is required to ensure that malicious apps run by the user cannot use the user’s credentials to access services in unintended ways. This is particularly important since using the custom tokens option (as described above) disables Android’s own signature check when getting auth tokens.

  • Unless it is built into the account authenticator, the system administrator or user will need to be able to configure the location of the key distribution center.

Security implications

Untrusted user

A user will be able to get a TGT if they can authorize themselves with the Kerberos Account Authenticator. To do this they must provide some information (typically a password) that matches information held by the key distribution center. Services they attempt to access will only provide access if the TGT is valid for that service. This is part of the normal Kerberos security model.

Untrusted SPNEGO Authenticator

Chrome will only use the SPNEGO Authenticator configured in its policies by the system administrator, so an untrusted authenticator will never be accessed by Chrome.

The authenticator service cannot decrypt a TGT from the keystore without information (typically a password) from the user that matches information held by the key distribution center. As such it cannot gain access to any services without user co-operation. Again, this is part of the normal Kerberos security model.

In addition, the first time an application attempts to use a new account from an authenticator with a different signature, the Android framework will inform the user and ask the user’s permission.

Note:- A sufficiently privileged malicious app (e.g. an app with root access) can, of course, bypass Chrome’s or Android’s security in other ways, however none of these threats are specific to SPNEGO Authenticators.

Untrusted Application

The authenticator knows what application is requesting a token, and can hence refuse tokens to unauthorized applications. Even if the authenticator fails to do this the untrusted application will only have access to services for which the user is already authorized. In addition, the first time a new application attempts to use an account from an authenticator with a different signature, the Android framework will inform the user and ask the user’s permission.
 


[1] The problem here is that Android, without this option, automatically caches the results of all successful authToken requests, keyed only on the account and token type. As a result it will incorrectly cache the result of intermediate steps during multi-step authentication.