chromium/net/http/http_auth_gssapi_posix.h

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
#define NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_

#include <string>
#include <string_view>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/native_library.h"
#include "base/values.h"
#include "build/build_config.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_export.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_mechanism.h"

#if BUILDFLAG(IS_APPLE)
#include <GSS/gssapi.h>
#elif BUILDFLAG(IS_FREEBSD)
#include <gssapi/gssapi.h>
#else
#include <gssapi.h>
#endif

namespace net {

class HttpAuthChallengeTokenizer;

// Mechanism OID for GSSAPI. We always use SPNEGO.
NET_EXPORT_PRIVATE extern gss_OID CHROME_GSS_SPNEGO_MECH_OID_DESC;

// GSSAPILibrary is introduced so unit tests can mock the calls to the GSSAPI
// library. The default implementation attempts to load one of the standard
// GSSAPI library implementations, then simply passes the arguments on to
// that implementation.
class NET_EXPORT_PRIVATE GSSAPILibrary {};

// GSSAPISharedLibrary class is defined here so that unit tests can access it.
class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {};

// ScopedSecurityContext releases a gss_ctx_id_t when it goes out of
// scope.
class ScopedSecurityContext {};


// TODO(ahendrickson): Share code with HttpAuthSSPI.
class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpAuthMechanism {};

// Diagnostics

// GetGssStatusCodeValue constructs a base::Value::Dict containing a status code
// and a message.
//
//     {
//       "status" : <status value as a number>,
//       "message": [
//          <list of strings explaining what that number means>
//       ]
//     }
//
// Messages are looked up via gss_display_status() exposed by |gssapi_lib|. The
// type of status code should be indicated by setting |status_code_type| to
// either |GSS_C_MECH_CODE| or |GSS_C_GSS_CODE|.
//
// Mechanism specific codes aren't unique, so the mechanism needs to be
// identified to look up messages if |status_code_type| is |GSS_C_MECH_CODE|.
// Since no mechanism OIDs are passed in, mechanism specific status codes will
// likely not have messages.
NET_EXPORT_PRIVATE base::Value::Dict GetGssStatusCodeValue(
    GSSAPILibrary* gssapi_lib,
    OM_uint32 status,
    OM_uint32 status_code_type);

// Given major and minor GSSAPI status codes, returns a base::Value::Dict
// encapsulating the codes as well as their meanings as expanded via
// gss_display_status().
//
// The base::Value::Dict has the following structure:
//   {
//     "function": <name of GSSAPI function that returned the error>
//     "major_status": {
//       "status" : <status value as a number>,
//       "message": [
//          <list of strings hopefully explaining what that number means>
//       ]
//     },
//     "minor_status": {
//       "status" : <status value as a number>,
//       "message": [
//          <list of strings hopefully explaining what that number means>
//       ]
//     }
//   }
//
// Passing nullptr to |gssapi_lib| will skip the message lookups. Thus the
// returned value will be missing the "message" fields. The same is true if the
// message lookup failed for some reason, or if the lookups succeeded but
// yielded an empty message.
NET_EXPORT_PRIVATE base::Value::Dict GetGssStatusValue(
    GSSAPILibrary* gssapi_lib,
    std::string_view method,
    OM_uint32 major_status,
    OM_uint32 minor_status);

// OidToValue returns a base::Value::Dict representing an OID. The structure of
// the value is:
//   {
//     "oid":    <symbolic name of OID if it is known>
//     "length": <length in bytes of serialized OID>,
//     "bytes":  <hexdump of up to 1024 bytes of serialized OID>
//   }
NET_EXPORT_PRIVATE base::Value::Dict OidToValue(const gss_OID oid);

// GetDisplayNameValue returns a base::Value::Dict representing a gss_name_t. It
// invokes |gss_display_name()| via |gssapi_lib| to determine the display name
// associated with |gss_name|.
//
// The structure of the returned value is:
//   {
//     "gss_name": <display name as returned by gss_display_name()>,
//     "type": <OID indicating type. See OidToValue() for structure of this
//              field>
//   }
//
// If the lookup failed, then the structure is:
//   {
//     "error": <error. See GetGssStatusValue() for structure.>
//   }
//
// Note that |gss_name_t| is platform dependent. If |gss_display_name| fails,
// there's no good value to display in its stead.
NET_EXPORT_PRIVATE base::Value::Dict GetDisplayNameValue(
    GSSAPILibrary* gssapi_lib,
    const gss_name_t gss_name);

// GetContextStateAsValue returns a base::Value::Dict that describes the state
// of a GSSAPI context. The structure of the value is:
//
//   {
//     "source": {
//       "name": <GSSAPI principal name of source (e.g. the user)>,
//       "type": <OID of name type>
//     },
//     "target": {
//       "name": <GSSAPI principal name of target (e.g. the server)>,
//       "type": <OID of name type>
//     },
//     "lifetime": <Lifetime of the negotiated context in seconds.>,
//     "mechanism": <OID of negotiated mechanism>,
//     "flags": <Context flags. See documentation for gss_inquire_context for
//               flag values>
//     "open": <True if the context has finished the handshake>
//   }
//
// If the inquiry fails, the following is returned:
//   {
//     "error": <error. See GetGssStatusValue() for structure.>
//   }
NET_EXPORT_PRIVATE base::Value::Dict GetContextStateAsValue(
    GSSAPILibrary* gssapi_lib,
    const gss_ctx_id_t context_handle);
}  // namespace net

#endif  // NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_