Projects/Credential cache collection improvements
This project intends to formalize the concept of a credential cache collection and improve the behavior of programs and library functions which store initial credentials within a collection.
The concept of a credential cache collection began in release 1.6 with the introduction of the krb5_cccol APIs. In release 1.10, the client principal selection project implemented the collection-enabled DIR credential cache type, collection behavior for kinit, klist, and kdestroy, and added the new kswitch command. The behavior of tools on credential cache collections was based largely on the behavior of Heimdal, whose collection semantics in turn were based loosely on Kerberos for Macintosh.
Credential cache types are either collection-enabled (such as DIR) or not (such as FILE). For a collection-enabled type, the residual string may identify a collection (such as DIR:/path/to/directory) or a subsidiary cache within the collection (such as DIR::/path/to/directory/tktXXXXXX). A collection has a primary cache which can be altered by krb5_cc_switch or the kswitch command. Resolving the name of a collection yields a cache handle for the primary cache within that collection.
The krb5_cccol APIs define "the collection" as the union of all per-type collections. These APIs do not accept the name of a particular collection, but the default ccache name of the krb5_context object influences what is in per-type collections. Except for MEMORY and API, no ccache type adds caches to the collection unless it is used by the default ccache name. If the default ccache name indicates a subsidiary cache for a collection-enabled type, the ccache type only adds the subsidiary cache to the collection, not the full collection contents.
ccache type implementations of krb5_cc_new_unique may also use the default ccache name to determine what collection to create a new cache in.
GSSAPI client applications will automatically select caches from the collection based on the $HOME/.k5identity file or the realm of the target server.
If the default cache name uses a switchable type, kinit will scan the collection for a cache with the same principal as it is acquiring credentials for, and will refresh that cache if one is found. If one is not found, it will create a new cache of the same type using krb5_cc_new_unique. When credentials are successfully acquired, the ccache used will be made the primary cache for the collection using krb5_cc_switch.
The krb5 GSSAPI mechanism's gss_acquire_cred uses similar logic to pick a cache when acquiring new credentials, with a few differences: (1) if the default cache type is not switchable, it will not overwrite existing credentials in the default cache unless they have the same client principal name; (2) when acquiring credentials with a password, it will prefer an uninitialized primary cache to a new cache within the collection; and (3) it never switches the primary cache within the collection.
ksu also uses similar logic to kinit to pick a cache, operating on the default cache name of the target user. It never switches the primary cache within the collection. If the default cache type is not switchable, it does not overwrite the default cache; instead, it creates a unique cache name by extending the default cache name.
gss_store_cred does not yet implement collection semantics; see [krbdev.mit.edu #8010].
There are inherent concurrency issues in the cache collection and base credential cache API functions. Two processes obtaining new credentials within a collection for the same principal at the same time could wind up creating separate unique caches within the collection, instead of choosing the same cache. [krbdev.mit.edu #7707] describes issues surrounding atomic reinitialization of caches, and proposes using krb5_cc_move to solve them.
New collection architecture
As before, a credential cache name identifies either a collection or an individual cache, a collection has a switchable primary cache, and resolving a collection name results in a handle to the primary cache. For collection-enabled cache types, a new method will distinguish between residual strings which identify collections and residual strings which identify individual caches.
New APIs will allow operation on named collections, using a credential cache name to identify the collection. Where it makes sense for these APIs, a credential cache name identifying a single cache will be treated as a singleton collection containing only one cache. Existing APIs will operate on the default cache name of the krb5_context object. There will no longer be a global connection containing the union of per-type collections; as the collection APIs always operate on a ccache name, iterating over the collection will yield only caches of one type. New APIs will be needed to amend krb5_cccol_cursor_new, krb5_cc_cache_match, krb5_cc_new_unique, and krb5_cc_switch. (TBD: flesh out these new APIs.)
A new API will copy credentials from an existing cache (typically a MEMORY cache) into a named collection, optionally replacing credentials and switching the primary cache. This API can operate atomically when the cache type permits. kinit, gss_acquire_cred, gss_store_cred, gss_store_cred_into, and ksu will be modified to use this API. The same API can be used to reinitialize a specific cache by specifying a cache name instead of a collection name. (TBD: flesh out these new APIs. Open question: if there is a flag for setting the default, should we insist on it being set if the ccname is not a collection?)
MEMORY and API caches will no longer appear within the collection when the default cache name does not use those types.
If the default cache name uses a switchable type but identifies a single cache within the collection, kinit/gss_acquire_cred/ksu will store into that specific cache rather than trying to apply collection semantics.
kinit -c and gss_store_cred_into, when given a ccache name identifying a collection, will use collection semantics for choosing a cache within the collection, rather than storing into the primary cache of the collection.
A new kinit option (probably -N, and --no-change-default if long options are supported) will allow obtaining new tickets with kinit without switching the default. (Open question: if the specified ccache name is not a collection and the cache contains credentials for a different principal, should this fail?)
kswitch will intuit the -c or -p flag based on the argument. If the argument begins with a / or \ or contains a colon, we will assume that it is a cache name (-c); otherwise we will assume that it is a principal name (-p). If additional arguments are given, they will be treated as a command to be run with the selected cache as the default cache, and the primary cache of the collection will remain unchanged. This will allow usage like "kinit -N user/root" followed by kswitch user/root ssh root@hostname".
We will add new pages to doc/user and to doc/appdev describing cache collections from the user and API viewpoints.
The existing documentation of collection behavior in gssapi.rst, ccache_def.rst, ccselect.rst, klist.rst, kinit.rst, kswitch.rst, kdestroy.rst, k5identity.rst, env_variables.rst, and krb5_conf.rst will be updated to reflect the new architecture.