http_auth_gssapi_posix.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
  5. #define NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
  6. #include <string>
  7. #include "base/gtest_prod_util.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/native_library.h"
  10. #include "base/strings/string_piece_forward.h"
  11. #include "base/values.h"
  12. #include "build/build_config.h"
  13. #include "net/base/completion_once_callback.h"
  14. #include "net/base/net_export.h"
  15. #include "net/http/http_auth.h"
  16. #include "net/http/http_auth_mechanism.h"
  17. #if BUILDFLAG(IS_APPLE)
  18. #include <GSS/gssapi.h>
  19. #elif BUILDFLAG(IS_FREEBSD)
  20. #include <gssapi/gssapi.h>
  21. #else
  22. #include <gssapi.h>
  23. #endif
  24. namespace net {
  25. class HttpAuthChallengeTokenizer;
  26. // Mechanism OID for GSSAPI. We always use SPNEGO.
  27. NET_EXPORT_PRIVATE extern gss_OID CHROME_GSS_SPNEGO_MECH_OID_DESC;
  28. // GSSAPILibrary is introduced so unit tests can mock the calls to the GSSAPI
  29. // library. The default implementation attempts to load one of the standard
  30. // GSSAPI library implementations, then simply passes the arguments on to
  31. // that implementation.
  32. class NET_EXPORT_PRIVATE GSSAPILibrary {
  33. public:
  34. virtual ~GSSAPILibrary() = default;
  35. // Initializes the library, including any necessary dynamic libraries.
  36. // This is done separately from construction (which happens at startup time)
  37. // in order to delay work until the class is actually needed.
  38. virtual bool Init(const NetLogWithSource& net_log) = 0;
  39. // These methods match the ones in the GSSAPI library.
  40. virtual OM_uint32 import_name(
  41. OM_uint32* minor_status,
  42. const gss_buffer_t input_name_buffer,
  43. const gss_OID input_name_type,
  44. gss_name_t* output_name) = 0;
  45. virtual OM_uint32 release_name(
  46. OM_uint32* minor_status,
  47. gss_name_t* input_name) = 0;
  48. virtual OM_uint32 release_buffer(
  49. OM_uint32* minor_status,
  50. gss_buffer_t buffer) = 0;
  51. virtual OM_uint32 display_name(
  52. OM_uint32* minor_status,
  53. const gss_name_t input_name,
  54. gss_buffer_t output_name_buffer,
  55. gss_OID* output_name_type) = 0;
  56. virtual OM_uint32 display_status(
  57. OM_uint32* minor_status,
  58. OM_uint32 status_value,
  59. int status_type,
  60. const gss_OID mech_type,
  61. OM_uint32* message_contex,
  62. gss_buffer_t status_string) = 0;
  63. virtual OM_uint32 init_sec_context(
  64. OM_uint32* minor_status,
  65. const gss_cred_id_t initiator_cred_handle,
  66. gss_ctx_id_t* context_handle,
  67. const gss_name_t target_name,
  68. const gss_OID mech_type,
  69. OM_uint32 req_flags,
  70. OM_uint32 time_req,
  71. const gss_channel_bindings_t input_chan_bindings,
  72. const gss_buffer_t input_token,
  73. gss_OID* actual_mech_type,
  74. gss_buffer_t output_token,
  75. OM_uint32* ret_flags,
  76. OM_uint32* time_rec) = 0;
  77. virtual OM_uint32 wrap_size_limit(
  78. OM_uint32* minor_status,
  79. const gss_ctx_id_t context_handle,
  80. int conf_req_flag,
  81. gss_qop_t qop_req,
  82. OM_uint32 req_output_size,
  83. OM_uint32* max_input_size) = 0;
  84. virtual OM_uint32 delete_sec_context(
  85. OM_uint32* minor_status,
  86. gss_ctx_id_t* context_handle,
  87. gss_buffer_t output_token) = 0;
  88. virtual OM_uint32 inquire_context(
  89. OM_uint32* minor_status,
  90. const gss_ctx_id_t context_handle,
  91. gss_name_t* src_name,
  92. gss_name_t* targ_name,
  93. OM_uint32* lifetime_rec,
  94. gss_OID* mech_type,
  95. OM_uint32* ctx_flags,
  96. int* locally_initiated,
  97. int* open) = 0;
  98. virtual const std::string& GetLibraryNameForTesting() = 0;
  99. };
  100. // GSSAPISharedLibrary class is defined here so that unit tests can access it.
  101. class NET_EXPORT_PRIVATE GSSAPISharedLibrary : public GSSAPILibrary {
  102. public:
  103. // If |gssapi_library_name| is empty, hard-coded default library names are
  104. // used.
  105. explicit GSSAPISharedLibrary(const std::string& gssapi_library_name);
  106. ~GSSAPISharedLibrary() override;
  107. // GSSAPILibrary methods:
  108. bool Init(const NetLogWithSource& net_log) override;
  109. OM_uint32 import_name(OM_uint32* minor_status,
  110. const gss_buffer_t input_name_buffer,
  111. const gss_OID input_name_type,
  112. gss_name_t* output_name) override;
  113. OM_uint32 release_name(OM_uint32* minor_status,
  114. gss_name_t* input_name) override;
  115. OM_uint32 release_buffer(OM_uint32* minor_status,
  116. gss_buffer_t buffer) override;
  117. OM_uint32 display_name(OM_uint32* minor_status,
  118. const gss_name_t input_name,
  119. gss_buffer_t output_name_buffer,
  120. gss_OID* output_name_type) override;
  121. OM_uint32 display_status(OM_uint32* minor_status,
  122. OM_uint32 status_value,
  123. int status_type,
  124. const gss_OID mech_type,
  125. OM_uint32* message_contex,
  126. gss_buffer_t status_string) override;
  127. OM_uint32 init_sec_context(OM_uint32* minor_status,
  128. const gss_cred_id_t initiator_cred_handle,
  129. gss_ctx_id_t* context_handle,
  130. const gss_name_t target_name,
  131. const gss_OID mech_type,
  132. OM_uint32 req_flags,
  133. OM_uint32 time_req,
  134. const gss_channel_bindings_t input_chan_bindings,
  135. const gss_buffer_t input_token,
  136. gss_OID* actual_mech_type,
  137. gss_buffer_t output_token,
  138. OM_uint32* ret_flags,
  139. OM_uint32* time_rec) override;
  140. OM_uint32 wrap_size_limit(OM_uint32* minor_status,
  141. const gss_ctx_id_t context_handle,
  142. int conf_req_flag,
  143. gss_qop_t qop_req,
  144. OM_uint32 req_output_size,
  145. OM_uint32* max_input_size) override;
  146. OM_uint32 delete_sec_context(OM_uint32* minor_status,
  147. gss_ctx_id_t* context_handle,
  148. gss_buffer_t output_token) override;
  149. OM_uint32 inquire_context(OM_uint32* minor_status,
  150. const gss_ctx_id_t context_handle,
  151. gss_name_t* src_name,
  152. gss_name_t* targ_name,
  153. OM_uint32* lifetime_rec,
  154. gss_OID* mech_type,
  155. OM_uint32* ctx_flags,
  156. int* locally_initiated,
  157. int* open) override;
  158. const std::string& GetLibraryNameForTesting() override;
  159. private:
  160. FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup);
  161. bool InitImpl(const NetLogWithSource& net_log);
  162. // Finds a usable dynamic library for GSSAPI and loads it. The criteria are:
  163. // 1. The library must exist.
  164. // 2. The library must export the functions we need.
  165. base::NativeLibrary LoadSharedLibrary(const NetLogWithSource& net_log);
  166. bool BindMethods(base::NativeLibrary lib,
  167. base::StringPiece library_name,
  168. const NetLogWithSource& net_log);
  169. bool initialized_ = false;
  170. std::string gssapi_library_name_;
  171. // Need some way to invalidate the library.
  172. base::NativeLibrary gssapi_library_ = nullptr;
  173. // Function pointers
  174. decltype(&gss_import_name) import_name_ = nullptr;
  175. decltype(&gss_release_name) release_name_ = nullptr;
  176. decltype(&gss_release_buffer) release_buffer_ = nullptr;
  177. decltype(&gss_display_name) display_name_ = nullptr;
  178. decltype(&gss_display_status) display_status_ = nullptr;
  179. decltype(&gss_init_sec_context) init_sec_context_ = nullptr;
  180. decltype(&gss_wrap_size_limit) wrap_size_limit_ = nullptr;
  181. decltype(&gss_delete_sec_context) delete_sec_context_ = nullptr;
  182. decltype(&gss_inquire_context) inquire_context_ = nullptr;
  183. };
  184. // ScopedSecurityContext releases a gss_ctx_id_t when it goes out of
  185. // scope.
  186. class ScopedSecurityContext {
  187. public:
  188. explicit ScopedSecurityContext(GSSAPILibrary* gssapi_lib);
  189. ScopedSecurityContext(const ScopedSecurityContext&) = delete;
  190. ScopedSecurityContext& operator=(const ScopedSecurityContext&) = delete;
  191. ~ScopedSecurityContext();
  192. gss_ctx_id_t get() const { return security_context_; }
  193. gss_ctx_id_t* receive() { return &security_context_; }
  194. private:
  195. gss_ctx_id_t security_context_ = GSS_C_NO_CONTEXT;
  196. raw_ptr<GSSAPILibrary> gssapi_lib_;
  197. };
  198. // TODO(ahendrickson): Share code with HttpAuthSSPI.
  199. class NET_EXPORT_PRIVATE HttpAuthGSSAPI : public HttpAuthMechanism {
  200. public:
  201. HttpAuthGSSAPI(GSSAPILibrary* library,
  202. const gss_OID gss_oid);
  203. ~HttpAuthGSSAPI() override;
  204. // HttpAuthMechanism implementation:
  205. bool Init(const NetLogWithSource& net_log) override;
  206. bool NeedsIdentity() const override;
  207. bool AllowsExplicitCredentials() const override;
  208. HttpAuth::AuthorizationResult ParseChallenge(
  209. HttpAuthChallengeTokenizer* tok) override;
  210. int GenerateAuthToken(const AuthCredentials* credentials,
  211. const std::string& spn,
  212. const std::string& channel_bindings,
  213. std::string* auth_token,
  214. const NetLogWithSource& net_log,
  215. CompletionOnceCallback callback) override;
  216. void SetDelegation(HttpAuth::DelegationType delegation_type) override;
  217. private:
  218. int GetNextSecurityToken(const std::string& spn,
  219. const std::string& channel_bindings,
  220. gss_buffer_t in_token,
  221. gss_buffer_t out_token,
  222. const NetLogWithSource& net_log);
  223. gss_OID gss_oid_;
  224. raw_ptr<GSSAPILibrary> library_;
  225. std::string decoded_server_auth_token_;
  226. ScopedSecurityContext scoped_sec_context_;
  227. HttpAuth::DelegationType delegation_type_ = HttpAuth::DelegationType::kNone;
  228. };
  229. // Diagnostics
  230. // GetGssStatusCodeValue constructs a base::Value::Dict containing a status code
  231. // and a message.
  232. //
  233. // {
  234. // "status" : <status value as a number>,
  235. // "message": [
  236. // <list of strings explaining what that number means>
  237. // ]
  238. // }
  239. //
  240. // Messages are looked up via gss_display_status() exposed by |gssapi_lib|. The
  241. // type of status code should be indicated by setting |status_code_type| to
  242. // either |GSS_C_MECH_CODE| or |GSS_C_GSS_CODE|.
  243. //
  244. // Mechanism specific codes aren't unique, so the mechanism needs to be
  245. // identified to look up messages if |status_code_type| is |GSS_C_MECH_CODE|.
  246. // Since no mechanism OIDs are passed in, mechanism specific status codes will
  247. // likely not have messages.
  248. NET_EXPORT_PRIVATE base::Value::Dict GetGssStatusCodeValue(
  249. GSSAPILibrary* gssapi_lib,
  250. OM_uint32 status,
  251. OM_uint32 status_code_type);
  252. // Given major and minor GSSAPI status codes, returns a base::Value::Dict
  253. // encapsulating the codes as well as their meanings as expanded via
  254. // gss_display_status().
  255. //
  256. // The base::Value has the following structure:
  257. // {
  258. // "function": <name of GSSAPI function that returned the error>
  259. // "major_status": {
  260. // "status" : <status value as a number>,
  261. // "message": [
  262. // <list of strings hopefully explaining what that number means>
  263. // ]
  264. // },
  265. // "minor_status": {
  266. // "status" : <status value as a number>,
  267. // "message": [
  268. // <list of strings hopefully explaining what that number means>
  269. // ]
  270. // }
  271. // }
  272. //
  273. // Passing nullptr to |gssapi_lib| will skip the message lookups. Thus the
  274. // returned value will be missing the "message" fields. The same is true if the
  275. // message lookup failed for some reason, or if the lookups succeeded but
  276. // yielded an empty message.
  277. NET_EXPORT_PRIVATE base::Value::Dict GetGssStatusValue(
  278. GSSAPILibrary* gssapi_lib,
  279. base::StringPiece method,
  280. OM_uint32 major_status,
  281. OM_uint32 minor_status);
  282. // OidToValue returns a base::Value::Dict representing an OID. The structure of
  283. // the value is:
  284. // {
  285. // "oid": <symbolic name of OID if it is known>
  286. // "length": <length in bytes of serialized OID>,
  287. // "bytes": <hexdump of up to 1024 bytes of serialized OID>
  288. // }
  289. NET_EXPORT_PRIVATE base::Value::Dict OidToValue(const gss_OID oid);
  290. // GetDisplayNameValue returns a base::Value::Dict representing a gss_name_t. It
  291. // invokes |gss_display_name()| via |gssapi_lib| to determine the display name
  292. // associated with |gss_name|.
  293. //
  294. // The structure of the returned value is:
  295. // {
  296. // "gss_name": <display name as returned by gss_display_name()>,
  297. // "type": <OID indicating type. See OidToValue() for structure of this
  298. // field>
  299. // }
  300. //
  301. // If the lookup failed, then the structure is:
  302. // {
  303. // "error": <error. See GetGssStatusValue() for structure.>
  304. // }
  305. //
  306. // Note that |gss_name_t| is platform dependent. If |gss_display_name| fails,
  307. // there's no good value to display in its stead.
  308. NET_EXPORT_PRIVATE base::Value::Dict GetDisplayNameValue(
  309. GSSAPILibrary* gssapi_lib,
  310. const gss_name_t gss_name);
  311. // GetContextStateAsValue returns a base::Value that describes the state of a
  312. // GSSAPI context. The structure of the value is:
  313. //
  314. // {
  315. // "source": {
  316. // "name": <GSSAPI principal name of source (e.g. the user)>,
  317. // "type": <OID of name type>
  318. // },
  319. // "target": {
  320. // "name": <GSSAPI principal name of target (e.g. the server)>,
  321. // "type": <OID of name type>
  322. // },
  323. // "lifetime": <Lifetime of the negotiated context in seconds.>,
  324. // "mechanism": <OID of negotiated mechanism>,
  325. // "flags": <Context flags. See documentation for gss_inquire_context for
  326. // flag values>
  327. // "open": <True if the context has finished the handshake>
  328. // }
  329. //
  330. // If the inquiry fails, the following is returned:
  331. // {
  332. // "error": <error. See GetGssStatusValue() for structure.>
  333. // }
  334. NET_EXPORT_PRIVATE base::Value GetContextStateAsValue(
  335. GSSAPILibrary* gssapi_lib,
  336. const gss_ctx_id_t context_handle);
  337. } // namespace net
  338. #endif // NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_