/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 * Copyright 2005-2006 Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 * require a specific license from the United States Government.
 * It is the responsibility of any person or organization contemplating
 * export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 */

#ifndef KIM_SELECTION_HINTS_H
#define KIM_SELECTION_HINTS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <kim/kim_types.h>

/*!
 * \page kim_selection_hints_overview KIM Selection Hints Overview
 *
 * \section kim_selection_hints_introduction Introduction
 *
 * Most users belong to multiple organizations and thus need
 * to authenticate to multiple Kerberos realms.  Traditionally Kerberos sites
 * solved this problem by setting up a cross-realm relationship, which allowed
 * the user to use TGT credentials for their client identity in one realm
 * to obtain credentials in another realm via cross-realm authentication.  As a
 * result users could acquire credentials for a single client identity and use
 * them everywhere.
 *
 * Setting up cross-realm requires that realms share a secret, so sites must
 * coordinate with one another to set up a cross-realm relationship.  In
 * addition, sites must set up authorization policies for users from other
 * realms.  As Kerberos becomes increasingly wide-spread, many realms will
 * not have cross-realm relationships, and users will need to
 * manually obtain credentials for their client identity at each realm
 * (eg: "user@BANK.COM", "user@UNIVERSITY.EDU", etc).  As a result, users
 * will often have multiple credentials caches, one for each client identity.
 *
 * Unfortunately this presents a problem for applications which need to obtain
 * service credentials.  Which client identity should they use?
 * Rather than having each application to manually search the cache collection,
 * KIM provides a selection hints API for choosing the best client identity.
 * This API is intended to simplify the process of choosing credentials
 * and provide consistent behavior across all applications.
 *
 * Searching the cache collection for credentials may be expensive if there
 * are a large number of caches.  If credentials for the client identity
 * are expired or not present, KIM may also wish to prompt the user for
 * new credentials for the appropriate client identity.  As a result,
 * applications might want to remember which client identity worked in
 * the past and always request credentials using that identity.
 *
 *
 * \section kim_selection_hints_creating Creating KIM Selection Hints
 *
 * A KIM selection hints object consists of an application identifier and one or
 * more pieces of information about the service the client application will be
 * contacting.  The application identifier is used by user preferences
 * to control how applications share cache entries.  It is important to be
 * consistent about what application identifier you provide.  Java-style
 * identifiers are recommended to avoid collisions.
 *
 * \section kim_selection_hints_searching Selection Hint Search Behavior
 *
 * When using selection hints to search for an appropriate client identity,
 * KIM uses a consistent hint search order.  This allows applications to specify
 * potentially contradictory information without preventing KIM from locating a
 * single ccache.  In addition the selection hint search order may change,
 * especially if more hints are added.
 *
 * As a result, callers are encouraged to provide all relevant search hints,
 * even if only a subset of those search hints are necessary to get reasonable
 * behavior in the current implementation.  Doing so will provide the most
 * user-friendly selection experience.
 *
 * Currently the search order looks like this:
 *
 * \li <B>Service Identity</B> The client identity which has obtained a service credential for this service identity.
 * \li <B>Server</B> A client identity which has obtained a service credential for this server.
 * \li <B>Service Realm</B> A client identity which has obtained a service credential for this realm.
 * \li <B>Service</B> A client identity which has obtained a service credential for this service.
 * \li <B>Client Realm</B> A client identity in this realm.
 * \li <B>User</B> A client identity whose first component is this user string.
 *
 * For example, if you specify a service identity and a credential for
 * that identity already exists in the ccache collection, KIM may use that
 * ccache, even if your user and client realm entries in the selection hints would
 * lead it to choose a different ccache.  If no credentials for the service identity
 * exist then KIM will fall back on the user and realm hints.
 *
 * \note Due to performance and information exposure concerns, currently all
 * searching is done by examining the cache collection.  In the future the KIM
 * may also make network requests as part of its search algorithm.  For example
 * it might check to see if the TGT credentials in each ccache can obtain
 * credentials for the service identity specified by the selection hints.
 *
 * \section kim_selection_hints_selecting Selecting an Identity Using Selection Hints
 *
 * Once you have provided search criteria for selecting an identity, use
 * #kim_selection_hints_get_identity() to obtain an identity object.
 * You can then use #kim_identity_get_string() to obtain a krb5 principal
 * string for use with gss_import_name() and gss_acquire_cred().  Alternatively,
 * you can use #kim_ccache_create_from_client_identity() to obtain a ccache
 * containing credentials for the identity.
 *
 * \note #kim_selection_hints_get_identity() obtains an identity based on
 * the current state of the selection hints object.  If you change the
 * selection hints object you must call #kim_selection_hints_get_identity()
 * again.
 *
 * \section kim_selection_hints_caching Selection Hint Caching Behavior
 *
 * In addition to using selection hints to search for an appropriate client
 * identity, KIM can also use them to remember which client identity worked.
 * KIM maintains a per-user cache mapping selection hints to identities so
 * that applications do not have to maintain their own caches or present
 * user interface for selecting which cache to use.
 *
 * When #kim_selection_hints_get_identity() is called KIM looks up in the
 * cache and returns the identity which the selection hints map to.  If
 * there is not a preexisting cache entry for the selection hints then
 * #kim_selection_hints_get_identity() will search for an identity and
 * prompt the user if it cannot find an appropriate one.
 *
 * If the client identity returned by KIM authenticates and passes
 * authorization checks, you should tell KIM to cache the identity by calling
 * #kim_selection_hints_remember_identity().  This will create a cache entry
 * for the mapping between your selection hints and the identity so that
 * subsequent calls to #kim_selection_hints_get_identity() do not need to
 * prompt the user.
 *
 * If the client identity returned by KIM fails to authenticate or fails
 * authorization checks, you must call #kim_selection_hints_forget_identity()
 * to remove any mapping that already exists.  After this function is called,
 * future calls to #kim_selection_hints_get_identity() will search for an
 * identity again.  You may also wish to call this function if the user
 * changes your application preferences such that the identity might be
 * invalidated.
 *
 * \note It is very important that you call #kim_selection_hints_forget_identity()
 * if your application fails to successfully establish a connection with the
 * server. Otherwise the user can get "stuck" using the same non-working
 * identity if they chose the wrong one accidentally or if their identity
 * information changes.  Because only your application understands the
 * authorization checksof the protocol it uses, KIM cannot tell whether or not
 * the identity worked.
 *
 * If you wish to search and prompt for an identity without using
 * the cached mappings, you can turn off the cached mapping lookups using
 * #kim_selection_hints_set_remember_identity().  This is not recommended
 * for most applications since it will result in a lot of unnecessary
 * searching and prompting for identities.
 *
 * \note Because cache entries key off of selection hints, it is important
 * to always specify the same hints when contacting a particular
 * service.  Otherwise KIM will not always find the cache entries.
 *
 * \section kim_selection_hints_prompt Selection Hint Prompting Behavior
 *
 * If valid credentials for identity in the selection hints cache are
 * unavailable or if no identity could be found using searching or caching
 * when #kim_selection_hints_get_identity() is called, KIM may present a
 * GUI to ask the user to select an identity or acquire credentials for
 * an identity.
 *
 * \note Because of the caching behavior described above the user will
 * only be prompted to choose an identity when setting up the application
 * or when their identity stops working.
 *
 * In order to let the user know why Kerberos needs their assistance, KIM
 * displays the name of the application which requested the identity
 * selection. Unfortunately, some platforms do not provide a runtime
 * mechanism for determining the name of the calling process.  If your
 * application runs on one of these platforms (or is cross-platform)
 * you should provide a localized version of its name with
 * the private function #kim_library_set_application_name().
 *
 * In many cases a single application may select different identities for
 * different purposes.  For example an email application might use different
 * identities to check mail for different accounts.  If your application
 * has this property you may need to provide the user with a localized
 * string describing how the identity will be used.  You can specify
 * this string with #kim_selection_hints_get_explanation().  You can find
 * out what string will be used with kim_selection_hints_set_explanation().
 *
 * Since the user may choose to acquire credentials when selection an
 * identity, KIM also provides #kim_selection_hints_set_options() to
 * set what credential acquisition options are used.
 * #kim_selection_hints_get_options() returns the options which will be used.
 *
 * If you need to disable user interaction, use
 * #kim_selection_hints_set_allow_user_interaction().  Use
 * #kim_selection_hints_get_allow_user_interaction() to find out whether or
 * not user interaction is enabled.  User interaction is enabled by default.
 *
 * See \ref kim_selection_hints_reference for information on specific APIs.
 */

/*!
 * \defgroup kim_selection_hints_reference KIM Selection Hints Reference Documentation
 * @{
 */

/*! A client identity in this realm.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_client_realm     "kim_hint_key_client_realm"

/*! A client identity whose first component is this user string.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_user             "kim_hint_key_user"

/*! A client identity which has obtained a service credential for this realm.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_service_realm    "kim_hint_key_service_realm"

/*! A client identity which has obtained a service credential for this service.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_service          "kim_hint_key_service"

/*! A client identity which has obtained a service credential for this server.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_server           "kim_hint_key_server"

/*! The client identity which has obtained a service credential for this service identity.
 * See \ref kim_selection_hints_overview for more information */
#define kim_hint_key_service_identity "kim_hint_key_service_identity"

/*!
 * \param out_selection_hints       on exit, a new selection hints object.
 *                                  Must be freed with kim_selection_hints_free().
 * \param in_application_identifier an application identifier string.  Java-style identifiers are recommended
 *                                  to avoid cache entry collisions (eg: "com.example.MyApplication")
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Create a new selection hints object.
 */
kim_error kim_selection_hints_create (kim_selection_hints *out_selection_hints,
                                      kim_string           in_application_identifier);

/*!
 * \param out_selection_hints on exit, a new selection hints object which is a copy of in_selection_hints.
 *                            Must be freed with kim_selection_hints_free().
 * \param in_selection_hints  a selection hints object.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Copy a selection hints object.
 */
kim_error kim_selection_hints_copy (kim_selection_hints *out_selection_hints,
                                    kim_selection_hints  in_selection_hints);

/*!
 * \param io_selection_hints    a selection hints object to modify.
 * \param in_hint_key           A string representing the type of hint to set.
 * \param in_hint_string        A string representation of a hint for
 *                              \a in_hint_key to set in \a in_selection_hints.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Set the string value of a hint used for identity selection.
 * \sa kim_selection_hints_get_hint()
 */
kim_error kim_selection_hints_set_hint (kim_selection_hints io_selection_hints,
                                        kim_string          in_hint_key,
                                        kim_string          in_hint_string);

/*!
 * \param in_selection_hints    a selection hints object.
 * \param in_hint_key           A string representing the type of hint to
 *                              obtain.
 * \param out_hint_string       On exit, a string representation of the hint
 *                              \a in_hint_key in \a in_selection_hints.
 *                              If the hint is not set, sets the value pointed
 *                              to by \a out_hint_string to NULL;
 *                              Must be freed with kim_string_free().
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Get the string value of a hint used for identity selection.
 * \sa kim_selection_hints_set_hint()
 */
kim_error kim_selection_hints_get_hint (kim_selection_hints  in_selection_hints,
                                        kim_string           in_hint_key,
                                        kim_string          *out_hint_string);

/*!
 * \param io_selection_hints  a selection hints object to modify.
 * \param in_explanation      a localized string describing why the caller needs the identity.
 * \note If the application only does one thing (the reason it needs an identity is obvious)
 * then you may not need to call this function.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Set the strings used to prompt the user to select the identity.
 * \sa kim_selection_hints_get_explanation()
 */
kim_error kim_selection_hints_set_explanation (kim_selection_hints io_selection_hints,
                                               kim_string          in_explanation);

/*!
 * \param in_selection_hints   a selection hints object.
 * \param out_explanation      on exit, the localized string specified in \a in_selection_hints
 *                             which describes why the caller needs the identity.  May be NULL.
 *                             If non-NULL, must be freed with kim_string_free().
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Get the strings used to prompt the user to select the identity.
 * \sa kim_selection_hints_set_explanation()
 */
kim_error kim_selection_hints_get_explanation (kim_selection_hints  in_selection_hints,
                                               kim_string          *out_explanation);


/*!
 * \param io_selection_hints  a selection hints object to modify.
 * \param in_options          options to control credential acquisition.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Set the options which will be used if credentials need to be acquired.
 * \sa kim_selection_hints_get_options()
 */
kim_error kim_selection_hints_set_options (kim_selection_hints io_selection_hints,
                                           kim_options         in_options);

/*!
 * \param in_selection_hints a selection hints object.
 * \param out_options        on exit, the options to control credential acquisition
 *                           specified in \a in_selection_hints.  May be KIM_OPTIONS_DEFAULT.
 *                           If not, must be freed with kim_options_free().
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Get the options which will be used if credentials need to be acquired.
 * \sa kim_selection_hints_set_options()
 */
kim_error kim_selection_hints_get_options (kim_selection_hints  in_selection_hints,
                                           kim_options         *out_options);

/*!
 * \param in_selection_hints        a selection hints object to modify
 * \param in_allow_user_interaction a boolean value specifying whether or not KIM should ask
 *                                  the user to select an identity for \a in_selection_hints.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \note This setting defaults to TRUE.
 * \brief Set whether or not KIM may interact with the user to select an identity.
 * \sa kim_selection_hints_get_allow_user_interaction
 */
kim_error kim_selection_hints_set_allow_user_interaction (kim_selection_hints in_selection_hints,
                                                          kim_boolean         in_allow_user_interaction);

/*!
 * \param in_selection_hints         a selection hints object to modify
 * \param out_allow_user_interaction on exit, a boolean value specifying whether or not KIM
 *                                   should ask the user to select an identity for
 *                                   \a in_selection_hints.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \note This setting defaults to TRUE.
 * \brief Get whether or not KIM may interact with the user to select an identity.
 * \sa kim_selection_hints_set_allow_user_interaction
 */
kim_error kim_selection_hints_get_allow_user_interaction (kim_selection_hints  in_selection_hints,
                                                          kim_boolean         *out_allow_user_interaction);

/*!
 * \param in_selection_hints    a selection hints object to modify
 * \param in_remember_identity  a boolean value specifying whether or not KIM should use a cached
 *                              mapping between \a in_selection_hints and a Kerberos identity.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \note This setting defaults to TRUE.
 * \brief Set whether or not KIM will use cached mappings for this selection hints object.
 * \sa kim_selection_hints_get_remember_identity
 */
kim_error kim_selection_hints_set_remember_identity (kim_selection_hints in_selection_hints,
                                                     kim_boolean         in_remember_identity);

/*!
 * \param in_selection_hints     a selection hints object to modify
 * \param out_remember_identity on exit, a boolean value specifying whether or not KIM will use a
 *                               cached mapping between \a in_selection_hints and a Kerberos identity.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \note This setting defaults to TRUE.
 * \brief Get whether or not KIM will use cache mappings for this selection hints object.
 * \sa kim_selection_hints_set_remember_identity
 */
kim_error kim_selection_hints_get_remember_identity (kim_selection_hints  in_selection_hints,
                                                     kim_boolean         *out_remember_identity);

/*!
 * \param in_selection_hints the selection hints to add to the cache.
 * \param out_identity       the Kerberos identity \a in_selection_hints maps to.
 *                           Must be freed with kim_identity_free().
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \note \a out_identity is the identity mapped to by the current state of \a in_selection_hints.
 * This function may prompt the user via a GUI to choose that identity.
 * Subsequent modifications to \a in_selection_hints will not change \a out_identity.
 * \brief Choose a client identity based on selection hints.
 */

kim_error kim_selection_hints_get_identity (kim_selection_hints in_selection_hints,
                                            kim_identity        *out_identity);

/*!
 * \param in_selection_hints the selection hints to add to the cache.
 * \param in_identity the Kerberos identity \a in_selection_hints maps to.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Add an entry for the selection hints to the selection hints cache,
 * replacing any existing entry.
 */

kim_error kim_selection_hints_remember_identity (kim_selection_hints in_selection_hints,
                                                 kim_identity        in_identity);

/*!
 * \param in_selection_hints the selection hints to remove from the cache.
 * \return On success, #KIM_NO_ERROR.  On failure, an error code representing the failure.
 * \brief Remove an entry for the selection hints from the selection hints cache.
 */

kim_error kim_selection_hints_forget_identity (kim_selection_hints in_selection_hints);

/*!
 * \param io_selection_hints the selection hints object to be freed.  Set to NULL on exit.
 * \brief Free memory associated with a selection hints object.
 */

void kim_selection_hints_free (kim_selection_hints *io_selection_hints);

/*!@}*/

#ifdef __cplusplus
}
#endif

#endif /* KIM_SELECTION_HINTS_H */
