Documentation
¶
Overview ¶
Package http provides GSSAPI (Negotiate) enabled HTTP client and server implementations supporting RFC 4559.
import (
net/http
ghttp "github.com/golang-auth/go-gssapi/v3/http"
_ "github.com/golang-auth/go-gssapi-c"
)
p, err := gssapi.NewProvider("github.com/golang-auth/go-gssapi-c")
...
Clients and transorts ¶
Create a client to use a default GSSAPI enabled transport. The client can be used anywhere a standard http.Client can be used.
client, err := ghttp.NewClient(p, nil)
...
resp, err := client.Get("https://example.com")
...
req, err := http.NewRequest("GET", "http://example.com", nil)
...
req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)
...
To control GSSAPI parameters, create a transport:
transport := ghttp.NewTransport(
p,
http.WithOpportunistic(),
http.WithCredential(cred),
)
client := http.Client{Transport: transport}
resp, err := client.Get("https://example.com")
The GSSAPI enabled transport wraps a standard http.RoundTripper. By default it uses http.DefaultTransport. A custom round-tripper can be provided to the transport using WithRoundTripper.
Request body handling ¶
For HTTP methods such as POST, PUT, and others that include a request body, the client must send the full body to the server regardless of the server’s response code.
Starting with Go 1.8, the http.Request.GetBody method enables supported request body types to be rewound and resent if the server responds with a 401 Unauthorized challenge.
However, for large request bodies, retransmission can be inefficient.
One way to avoid sending large bodies multiple times is to use the Expect: 100-continue header.
Normal flow:
- The client sends headers first.
- If the server responds with 100 Continue, the client sends the body.
- If the server responds with 401 Unauthorized (or any final status) before sending 100 Continue, the client does not send the body.
This approach saves bandwidth when the request is likely to be challenged, but it depends on correct server implementation of 100-continue semantics.
Why this matters:
Under HTTP/1.1 (RFC 9110, §9), if the client sends a request with a Content-Length header and no Expect: 100-continue, then the server must either read and discard the entire body, or close the connection after sending the response.
This ensures leftover body bytes do not corrupt the interpretation of the next request over the same connection.
With Expect: 100-continue:
- The body is not sent until the server signals 100 Continue.
- If the server rejects early, there are no unread body bytes and the connection protocol stays clean without draining.
Client behavior:
Support for Expect: 100-continue is disabled by default due to implementation concerns with some servers.
It can be enabled by setting a threshold (in bytes) greater than zero.
When enabled, the client will add the header to requests that:
Do not have opportunistic authentication enabled, and
Either have a body size exceeding the threshold, or have a body that is not rewindable via GetBody.
The optimal threshold depends on factors such as network bandwidth, MTU, TLS overhead, and server 100-continue reliability.
The Go net/http server forces the connection to close after the reply when the client requests a 100-continue response.
- RFC view: If Content-Length is set, the client must send the full body, even without 100 Continue.
- Practical view: Closing avoids reading (and discarding) large unused bodies and prevents ambiguity in the TCP stream.
- Impact: When rejecting requests early (for example, 401 Unauthorized), the connection will close, requiring a new one for the retry.
For large request bodies and Negotiate authentication, this is generally preferable to draining the body.
Opportunistic authentication ¶
The GSSAPI enabled transport supports opportunistic authentication as described in RFC 4559 § 4.2 . The client does not wait for the server to respond with a 401 status code before sending an authentication token. This optimization can reduce round trips between the client and server, at the cost of initializing the GSSAPI context and potentially exposing authentication credentials to the server unnecessarily.
Servers ¶
Handler is a http.Handler that performs GSSAPI authentication and then calls the next handler with the initiator name in the request context.
Use Negotiate authentication for a subset of paths:
// Use Negotiate authentication for the /foo path
http.Handle("/foo", ghttp.NewHandler(p, fooHandler))
// but not for /bar
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServe(":8080", nil))
Use Negotiate authentication for all paths:
h := ghttp.NewHandler(p, http.DefaultServeMux)
log.Fatal(http.ListenAndServe(":8080", h))
Index ¶
- func NewClient(provider gssapi.Provider, client *http.Client, options ...ClientOption) *http.Client
- func WithHttpTrace(ctx context.Context, trace *HttpTrace) context.Context
- type ClientOption
- func WithCredential(cred gssapi.Credential) ClientOption
- func WithDelegationPolicy(delegationPolicy DelegationPolicy) ClientOption
- func WithExpect100Threshold(threshold int64) ClientOption
- func WithHttpLogging() ClientOption
- func WithLogFunc(logFunc func(format string, args ...interface{})) ClientOption
- func WithMutual() ClientOption
- func WithOpportunistic() ClientOption
- func WithOpportunisticFunc(opportunisticFunc OpportunisticFunc) ClientOption
- func WithRoundTripper(transport http.RoundTripper) ClientOption
- func WithSpnFunc(spnFunc SpnFunc) ClientOption
- type ContextKey
- type DelegationPolicy
- type GSSAPITransport
- type Handler
- type HandlerOption
- type HttpTrace
- type InitiatorName
- type OpportunisticFunc
- type SpnFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewClient ¶
NewClient returns a http.Client that uses GSSAPITransport to enable GSSAPI authentication.
If an existing client is provided, it will be copied and the http.RoundTripper will be replaced with a new GSSAPITransport. Otherwise the default http.Client will be used. The http.RoundTripper in the returned client will wrap the transport from the supplied client or http.DefaultTransport.
Types ¶
type ClientOption ¶
type ClientOption func(c *GSSAPITransport)
ClientOption is a function that configures a Client
func WithCredential ¶
func WithCredential(cred gssapi.Credential) ClientOption
WithCredential configures the client to use a specific credential
func WithDelegationPolicy ¶
func WithDelegationPolicy(delegationPolicy DelegationPolicy) ClientOption
WithDelegationPolicy configures the client to use a custom credential delegation policy.
func WithExpect100Threshold ¶
func WithExpect100Threshold(threshold int64) ClientOption
WithExpect100Threshold configures the client to use the Expect: Continue header if the request body is larger than the threshold.
Use of the Expect: Continue header is disabled by default due to concerns about the correct implementation by some servers.
func WithHttpLogging ¶
func WithHttpLogging() ClientOption
WithHttpLogging configures the client to log the HTTP requests and responses Does nothing without a log function
func WithLogFunc ¶
func WithLogFunc(logFunc func(format string, args ...interface{})) ClientOption
WithLogFunc configures the client to use a custom log function
func WithMutual ¶
func WithMutual() ClientOption
WithMutual configures the client to request mutual authentication
Mutual authentication means that the client and server both authenticate each other. It causes the server to respond with a GSSAPI authentication token in the Authorization header that the client can use to complete the context establishment and verify the server's identity.
func WithOpportunistic ¶
func WithOpportunistic() ClientOption
WithOpportunistic configures the client to opportunisticly authenticate
Opportunistic authentication means that the client does not wait for the server to respond with a 401 status code before sending an authentication token. This is a performance optimization that can be used to reduce the number of round trips between the client and server, at the cost of initializing the GSSAPI context and potentially exposing authentcation credentials to the server unnecessarily.
func WithOpportunisticFunc ¶
func WithOpportunisticFunc(opportunisticFunc OpportunisticFunc) ClientOption
WithOpportunisticFunc configures the client to use a custom function to determine if opportunistic authentication should be used for a given URL.
func WithRoundTripper ¶
func WithRoundTripper(transport http.RoundTripper) ClientOption
WithRoundTripper configures the client to use a custom round tripper
func WithSpnFunc ¶
func WithSpnFunc(spnFunc SpnFunc) ClientOption
WithSpnFunc provides a custom function to provide the Service Principal Name (SPN) for a given URL.
The default uses "HTTP@" + the host name of the URL.
type ContextKey ¶
type ContextKey int
type DelegationPolicy ¶
type DelegationPolicy int
DelegationPolicy is the policy for delegation of credentials to the server.
const ( // DelegationPolicyNever means that credentials will not be delegated to the server. DelegationPolicyNever DelegationPolicy = iota // DelegationPolicyAlways means that credentials will be delegated to the server. DelegationPolicyAlways // DelegationPolicyIfAllowed means that credentials will be delegated to the server // if the policy (eg. Kerberos OK-as-delegate policy) allows it. DelegationPolicyIfAllowed )
var DefaultDelegationPolicy DelegationPolicy = DelegationPolicyNever
DefaultDelegationPolicy is the default delegation policy used for new clients.
type GSSAPITransport ¶
type GSSAPITransport struct {
// contains filtered or unexported fields
}
GSSAPITransport is a http.RoundTripper implementation that includes GSSAPI (HTTP Negotiate) authentication.
func NewTransport ¶
func NewTransport(provider gssapi.Provider, options ...ClientOption) *GSSAPITransport
NewTransport creates a new GSSAPI transport with the given provider and options.
The transport is a wrapper around the standard http.Transport that adds GSSAPI authentication support. By default it wraps http.DefaultTransport - this can be overridden by passing a custom round tripper with WithRoundTripper.
func (*GSSAPITransport) RoundTrip ¶
RoundTrip implements the http.RoundTripper interface and performs one HTTP request, including potentially multiple round-trips to the server to complete the GSSAPI context establishment.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is a http.Handler that performs GSSAPI authentication and passes the initiator name to the next handler
func NewHandler ¶
NewHandler creates a new Handler with the given GSSAPI provider and next handler
func (*Handler) NegotiateOnce ¶
func (h *Handler) NegotiateOnce(negotiateToken string) (string, *InitiatorName, error)
NegotiateOnce performs a single GSSAPI round trip to establish the context and returns the output token and initiator name.
func (*Handler) ServeHTTP ¶
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP performs the GSSAPI authentication and passes the initiator name to the next handler It doesn't seem possible to support any more than one GSSAPI round trip per request with the Go http.Server implementation without hijacking the connection.
type HandlerOption ¶
type HandlerOption func(s *Handler)
HandlerOption is a function that can be used to configure the Handler
func WithAcceptorCredential ¶
func WithAcceptorCredential(credential gssapi.Credential) HandlerOption
WithAcceptorCredential sets the acceptor credential for the Handler
type HttpTrace ¶
HttpTrace gathers infromation during the HTTP request/response cycle.
func GetHttpTrace ¶
type InitiatorName ¶
type InitiatorName struct {
// PrincipalName is the fully qualified name of the initiator
PrincipalName string
// LocalName is the local name of the initiator if available
LocalName string
}
InitiatorName is the name of the initiator of the GSSAPI context. LocalName is set if the provider has the Localname extension
func GetInitiatorName ¶
func GetInitiatorName(r *http.Request) (*InitiatorName, bool)
GetInitiatorName returns the initiator name from the request context if available This can be used by the 'next' http handler called by Handler.ServeHTTP
type OpportunisticFunc ¶
OpportunisticFunc is a function that returns true if opportunistic authentication should be used for a given URL.