123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // 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 "base/gtest_prod_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/native_library.h"
- #include "base/strings/string_piece_forward.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 {
- public:
- virtual ~GSSAPILibrary() = default;
- // Initializes the library, including any necessary dynamic libraries.
- // This is done separately from construction (which happens at startup time)
- // in order to delay work until the class is actually needed.
- virtual bool Init(const NetLogWithSource& net_log) = 0;
- // These methods match the ones in the GSSAPI library.
- virtual OM_uint32 import_name(
- OM_uint32* minor_status,
- const gss_buffer_t input_name_buffer,
- const gss_OID input_name_type,
- gss_name_t* output_name) = 0;
- virtual OM_uint32 release_name(
- OM_uint32* minor_status,
- gss_name_t* input_name) = 0;
- virtual OM_uint32 release_buffer(
- OM_uint32* minor_status,
- gss_buffer_t buffer) = 0;
- virtual OM_uint32 display_name(
- OM_uint32* minor_status,
- const gss_name_t input_name,
- gss_buffer_t output_name_buffer,
- gss_OID* output_name_type) = 0;
- virtual OM_uint32 display_status(
- OM_uint32* minor_status,
- OM_uint32 status_value,
- int status_type,
- const gss_OID mech_type,
- OM_uint32* message_contex,
- gss_buffer_t status_string) = 0;
- virtual OM_uint32 init_sec_context(
- OM_uint32* minor_status,
- const gss_cred_id_t initiator_cred_handle,
- gss_ctx_id_t* context_handle,
- const gss_name_t target_name,
- const gss_OID mech_type,
- OM_uint32 req_flags,
- OM_uint32 time_req,
- const gss_channel_bindings_t input_chan_bindings,
- const gss_buffer_t input_token,
- gss_OID* actual_mech_type,
- gss_buffer_t output_token,
- OM_uint32* ret_flags,
- OM_uint32* time_rec) = 0;
- virtual OM_uint32 wrap_size_limit(
- OM_uint32* minor_status,
- const gss_ctx_id_t context_handle,
- int conf_req_flag,
- gss_qop_t qop_req,
- OM_uint32 req_output_size,
- OM_uint32* max_input_size) = 0;
- virtual OM_uint32 delete_sec_context(
- OM_uint32* minor_status,
- gss_ctx_id_t* context_handle,
- gss_buffer_t output_token) = 0;
- virtual OM_uint32 inquire_context(
- OM_uint32* minor_status,
- const gss_ctx_id_t context_handle,
- gss_name_t* src_name,
- gss_name_t* targ_name,
- OM_uint32* lifetime_rec,
- gss_OID* mech_type,
- OM_uint32* ctx_flags,
- int* locally_initiated,
- int* open) = 0;
- virtual const std::string& GetLibraryNameForTesting() = 0;
- };
- // GSSAPISharedLibrary class is defined here so that unit tests can access it.
- class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {
- public:
- // If |gssapi_library_name| is empty, hard-coded default library names are
- // used.
- explicit GSSAPISharedLibrary(const std::string& gssapi_library_name);
- ~GSSAPISharedLibrary() override;
- // GSSAPILibrary methods:
- bool Init(const NetLogWithSource& net_log) override;
- OM_uint32 import_name(OM_uint32* minor_status,
- const gss_buffer_t input_name_buffer,
- const gss_OID input_name_type,
- gss_name_t* output_name) override;
- OM_uint32 release_name(OM_uint32* minor_status,
- gss_name_t* input_name) override;
- OM_uint32 release_buffer(OM_uint32* minor_status,
- gss_buffer_t buffer) override;
- OM_uint32 display_name(OM_uint32* minor_status,
- const gss_name_t input_name,
- gss_buffer_t output_name_buffer,
- gss_OID* output_name_type) override;
- OM_uint32 display_status(OM_uint32* minor_status,
- OM_uint32 status_value,
- int status_type,
- const gss_OID mech_type,
- OM_uint32* message_contex,
- gss_buffer_t status_string) override;
- OM_uint32 init_sec_context(OM_uint32* minor_status,
- const gss_cred_id_t initiator_cred_handle,
- gss_ctx_id_t* context_handle,
- const gss_name_t target_name,
- const gss_OID mech_type,
- OM_uint32 req_flags,
- OM_uint32 time_req,
- const gss_channel_bindings_t input_chan_bindings,
- const gss_buffer_t input_token,
- gss_OID* actual_mech_type,
- gss_buffer_t output_token,
- OM_uint32* ret_flags,
- OM_uint32* time_rec) override;
- OM_uint32 wrap_size_limit(OM_uint32* minor_status,
- const gss_ctx_id_t context_handle,
- int conf_req_flag,
- gss_qop_t qop_req,
- OM_uint32 req_output_size,
- OM_uint32* max_input_size) override;
- OM_uint32 delete_sec_context(OM_uint32* minor_status,
- gss_ctx_id_t* context_handle,
- gss_buffer_t output_token) override;
- OM_uint32 inquire_context(OM_uint32* minor_status,
- const gss_ctx_id_t context_handle,
- gss_name_t* src_name,
- gss_name_t* targ_name,
- OM_uint32* lifetime_rec,
- gss_OID* mech_type,
- OM_uint32* ctx_flags,
- int* locally_initiated,
- int* open) override;
- const std::string& GetLibraryNameForTesting() override;
- private:
- FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup);
- bool InitImpl(const NetLogWithSource& net_log);
- // Finds a usable dynamic library for GSSAPI and loads it. The criteria are:
- // 1. The library must exist.
- // 2. The library must export the functions we need.
- base::NativeLibrary LoadSharedLibrary(const NetLogWithSource& net_log);
- bool BindMethods(base::NativeLibrary lib,
- base::StringPiece library_name,
- const NetLogWithSource& net_log);
- bool initialized_ = false;
- std::string gssapi_library_name_;
- // Need some way to invalidate the library.
- base::NativeLibrary gssapi_library_ = nullptr;
- // Function pointers
- decltype(&gss_import_name) import_name_ = nullptr;
- decltype(&gss_release_name) release_name_ = nullptr;
- decltype(&gss_release_buffer) release_buffer_ = nullptr;
- decltype(&gss_display_name) display_name_ = nullptr;
- decltype(&gss_display_status) display_status_ = nullptr;
- decltype(&gss_init_sec_context) init_sec_context_ = nullptr;
- decltype(&gss_wrap_size_limit) wrap_size_limit_ = nullptr;
- decltype(&gss_delete_sec_context) delete_sec_context_ = nullptr;
- decltype(&gss_inquire_context) inquire_context_ = nullptr;
- };
- // ScopedSecurityContext releases a gss_ctx_id_t when it goes out of
- // scope.
- class ScopedSecurityContext {
- public:
- explicit ScopedSecurityContext(GSSAPILibrary* gssapi_lib);
- ScopedSecurityContext(const ScopedSecurityContext&) = delete;
- ScopedSecurityContext& operator=(const ScopedSecurityContext&) = delete;
- ~ScopedSecurityContext();
- gss_ctx_id_t get() const { return security_context_; }
- gss_ctx_id_t* receive() { return &security_context_; }
- private:
- gss_ctx_id_t security_context_ = GSS_C_NO_CONTEXT;
- raw_ptr<GSSAPILibrary> gssapi_lib_;
- };
- // TODO(ahendrickson): Share code with HttpAuthSSPI.
- class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpAuthMechanism {
- public:
- HttpAuthGSSAPI(GSSAPILibrary* library,
- const gss_OID gss_oid);
- ~HttpAuthGSSAPI() override;
- // HttpAuthMechanism implementation:
- bool Init(const NetLogWithSource& net_log) override;
- bool NeedsIdentity() const override;
- bool AllowsExplicitCredentials() const override;
- HttpAuth::AuthorizationResult ParseChallenge(
- HttpAuthChallengeTokenizer* tok) override;
- int GenerateAuthToken(const AuthCredentials* credentials,
- const std::string& spn,
- const std::string& channel_bindings,
- std::string* auth_token,
- const NetLogWithSource& net_log,
- CompletionOnceCallback callback) override;
- void SetDelegation(HttpAuth::DelegationType delegation_type) override;
- private:
- int GetNextSecurityToken(const std::string& spn,
- const std::string& channel_bindings,
- gss_buffer_t in_token,
- gss_buffer_t out_token,
- const NetLogWithSource& net_log);
- gss_OID gss_oid_;
- raw_ptr<GSSAPILibrary> library_;
- std::string decoded_server_auth_token_;
- ScopedSecurityContext scoped_sec_context_;
- HttpAuth::DelegationType delegation_type_ = HttpAuth::DelegationType::kNone;
- };
- // 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 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,
- base::StringPiece 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 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 GetContextStateAsValue(
- GSSAPILibrary* gssapi_lib,
- const gss_ctx_id_t context_handle);
- } // namespace net
- #endif // NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
|