README.rst 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. requests GSSAPI authentication library
  2. ===============================================
  3. Requests is an HTTP library, written in Python, for human beings. This library
  4. adds optional GSSAPI authentication support and supports mutual
  5. authentication.
  6. It provides a fully backward-compatible shim for the old
  7. python-requests-kerberos library: simply replace ``import requests_kerberos``
  8. with ``import requests_gssapi``. A more powerful interface is provided by the
  9. HTTPSPNEGOAuth component, but this is of course not guaranteed to be
  10. compatible. Documentation below is written toward the new interface.
  11. Basic GET usage:
  12. .. code-block:: python
  13. >>> import requests
  14. >>> from requests_gssapi import HTTPSPNEGOAuth
  15. >>> r = requests.get("http://example.org", auth=HTTPSPNEGOAuth())
  16. ...
  17. The entire ``requests.api`` should be supported.
  18. Setup
  19. -----
  20. In order to use this library, there must already be a Kerberos Ticket-Granting
  21. Ticket (TGT) in a credential cache (ccache). Whether a TGT is available can
  22. be easily determined by running the ``klist`` command. If no TGT is
  23. available, then it first must be obtained (for instance, by running the
  24. ``kinit`` command, or pointing the $KRB5CCNAME to a credential cache with a
  25. valid TGT).
  26. In short, the library will handle the "negotiations" of Kerberos
  27. authentication, but ensuring that a credentials are available and valid is the
  28. responsibility of the user.
  29. Authentication Failures
  30. -----------------------
  31. Client authentication failures will be communicated to the caller by returning
  32. a 401 response. A 401 response may also be the result of expired credentials
  33. (including the TGT).
  34. Mutual Authentication
  35. ---------------------
  36. Mutual authentication is a poorly-named feature of the GSSAPI which doesn't
  37. provide any additional security benefit to most possible uses of
  38. requests_gssapi. Practically speaking, in most mechanism implementations
  39. (including krb5), it requires another round-trip between the client and server
  40. during the authentication handshake. Many clients and servers do not properly
  41. handle the authentication handshake taking more than one round-trip. If you
  42. encounter a MutualAuthenticationError, this is probably why.
  43. So long as you're running over a TLS link whose security guarantees you trust,
  44. there's no benefit to mutual authentication. If you don't trust the link at
  45. all, mutual authentication won't help (since it's not tamper-proof, and GSSAPI
  46. isn't being used post-authentication. There's some middle ground between the
  47. two where it helps a small amount (e.g., passive adversary over
  48. encrypted-but-unverified channel), but for Negotiate (what we're doing here),
  49. it's not generally helpful.
  50. For a more technical explanation of what mutual authentication actually
  51. guarantees, I refer you to rfc2743 (GSSAPIv2), rfc4120 (krb5 in GSSAPI),
  52. rfc4178 (SPNEGO), and rfc4559 (HTTP Negotiate).
  53. DISABLED
  54. ^^^^^^^^
  55. By default, there's no need to explicitly disable mutual authentication.
  56. However, for compatability with older versions of request_gssapi or
  57. requests_kerberos, you can explicitly request it not be attempted:
  58. .. code-block:: python
  59. >>> import requests
  60. >>> from requests_gssapi import HTTPSPNEGOAuth, DISABLED
  61. >>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=DISABLED)
  62. >>> r = requests.get("https://example.org", auth=gssapi_auth)
  63. ...
  64. REQUIRED
  65. ^^^^^^^^
  66. This was historically the default, but no longer is. If requested,
  67. ``HTTPSPNEGOAuth`` will require mutual authentication from the server, and if
  68. a server emits a non-error response which cannot be authenticated, a
  69. ``requests_gssapi.errors.MutualAuthenticationError`` will be raised. (See
  70. above for what this means.) If a server emits an error which cannot be
  71. authenticated, it will be returned to the user but with its contents and
  72. headers stripped. If the response content is more important than the need for
  73. mutual auth on errors, (eg, for certain WinRM calls) the stripping behavior
  74. can be suppressed by setting ``sanitize_mutual_error_response=False``:
  75. .. code-block:: python
  76. >>> import requests
  77. >>> from requests_gssapi import HTTPSPNEGOAuth, REQUIRED
  78. >>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=REQUIRED, sanitize_mutual_error_response=False)
  79. >>> r = requests.get("https://windows.example.org/wsman", auth=gssapi_auth)
  80. ...
  81. OPTIONAL
  82. ^^^^^^^^
  83. This will cause ``requests_gssapi`` to attempt mutual authentication if the
  84. server advertises that it supports it, and cause a failure if authentication
  85. fails, but not if the server does not support it at all. This is probably not
  86. what you want: link tampering will either cause hard failures, or silently
  87. cause it to not happen at all. It is retained for compatability.
  88. .. code-block:: python
  89. >>> import requests
  90. >>> from requests_gssapi import HTTPSPNEGOAuth, OPTIONAL
  91. >>> gssapi_auth = HTTPSPNEGOAuth(mutual_authentication=OPTIONAL)
  92. >>> r = requests.get("https://example.org", auth=gssapi_auth)
  93. ...
  94. Opportunistic Authentication
  95. ----------------------------
  96. ``HTTPSPNEGOAuth`` can be forced to preemptively initiate the GSSAPI
  97. exchange and present a token on the initial request (and all
  98. subsequent). By default, authentication only occurs after a
  99. ``401 Unauthorized`` response containing a Negotiate challenge
  100. is received from the origin server. This can cause mutual authentication
  101. failures for hosts that use a persistent connection (eg, Windows/WinRM), as
  102. no GSSAPI challenges are sent after the initial auth handshake. This
  103. behavior can be altered by setting ``opportunistic_auth=True``:
  104. .. code-block:: python
  105. >>> import requests
  106. >>> from requests_gssapi import HTTPSPNEGOAuth
  107. >>> gssapi_auth = HTTPSPNEGOAuth(opportunistic_auth=True)
  108. >>> r = requests.get("https://windows.example.org/wsman", auth=gssapi_auth)
  109. ...
  110. Hostname Override
  111. -----------------
  112. If communicating with a host whose DNS name doesn't match its
  113. hostname (eg, behind a content switch or load balancer),
  114. the hostname used for the GSSAPI exchange can be overridden by
  115. passing in a custom name (string or ``gssapi.Name``):
  116. .. code-block:: python
  117. >>> import requests
  118. >>> from requests_gssapi import HTTPSPNEGOAuth
  119. >>> gssapi_auth = HTTPSPNEGOAuth(target_name="internalhost.local")
  120. >>> r = requests.get("https://externalhost.example.org/", auth=gssapi_auth)
  121. ...
  122. Explicit Principal
  123. ------------------
  124. ``HTTPSPNEGOAuth`` normally uses the default principal (ie, the user for whom
  125. you last ran ``kinit`` or ``kswitch``, or an SSO credential if
  126. applicable). However, an explicit credential can be in instead, if desired.
  127. .. code-block:: python
  128. >>> import gssapi
  129. >>> import requests
  130. >>> from requests_gssapi import HTTPSPNEGOAuth
  131. >>> name = gssapi.Name("user@REALM", gssapi.NameType.hostbased_service)
  132. >>> creds = gssapi.Credentials(name=name, usage="initiate")
  133. >>> gssapi_auth = HTTPSPNEGOAuth(creds=creds)
  134. >>> r = requests.get("http://example.org", auth=gssapi_auth)
  135. ...
  136. Explicit Mechanism
  137. ------------------
  138. ``HTTPSPNEGOAuth`` normally lets the underlying ``gssapi`` library decide which
  139. negotiation mechanism to use. However, an explicit mechanism can be used instead
  140. if desired. The ``mech`` parameter will be passed straight through to ``gssapi``
  141. without interference. It is expected to be an instance of ``gssapi.mechs.Mechanism``.
  142. .. code-block:: python
  143. >>> import gssapi
  144. >>> import requests
  145. >>> from requests_gssapi import HTTPSPNEGOAuth
  146. >>> try:
  147. ... spnego = gssapi.mechs.Mechanism.from_sasl_name("SPNEGO")
  148. ... except AttributeError:
  149. ... spnego = gssapi.OID.from_int_seq("1.3.6.1.5.5.2")
  150. >>> gssapi_auth = HTTPSPNEGOAuth(mech=spnego)
  151. >>> r = requests.get("http://example.org", auth=gssapi_auth)
  152. ...
  153. Delegation
  154. ----------
  155. ``requests_gssapi`` supports credential delegation (``GSS_C_DELEG_FLAG``).
  156. To enable delegation of credentials to a server that requests delegation, pass
  157. ``delegate=True`` to ``HTTPSPNEGOAuth``:
  158. .. code-block:: python
  159. >>> import requests
  160. >>> from requests_gssapi import HTTPSPNEGOAuth
  161. >>> r = requests.get("http://example.org", auth=HTTPSPNEGOAuth(delegate=True))
  162. ...
  163. Be careful to only allow delegation to servers you trust as they will be able
  164. to impersonate you using the delegated credentials.
  165. Logging
  166. -------
  167. This library makes extensive use of Python's logging facilities.
  168. Log messages are logged to the ``requests_gssapi`` and
  169. ``requests_gssapi.gssapi`` named loggers.
  170. If you are having difficulty we suggest you configure logging. Issues with the
  171. underlying GSSAPI libraries will be made apparent. Additionally, copious debug
  172. information is made available which may assist in troubleshooting if you
  173. increase your log level all the way up to debug.