http

package
v3.0.0-beta5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 25, 2025 License: Apache-2.0 Imports: 10 Imported by: 0

README

GSSAPI enabled HTTP Client

The http package provides a GSSAPI-enabled HTTP client for Go applications.

Go Version GO Reference

Overview

The package provides a RoundTripper that adds GSSAPI authentication support as defined in RFC 4559.

Basic Usage

package main

import (
    "fmt"
    "log"
    
    "github.com/golang-auth/go-gssapi/v3"
    "github.com/golang-auth/go-gssapi/v3/http"
)

func main() {
    p := gssapi.MustNewProvider("github.com/golang-auth/go-gssapi-c")
    
    client := http.NewClient(p, nil)
    resp, err := client.Get("https://example.com")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    
    fmt.Println(resp.Status)
}

See the GoDoc reference for more detailed usage information.

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewClient

func NewClient(provider gssapi.Provider, client *http.Client, options ...ClientOption) *http.Client

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.

func WithHttpTrace

func WithHttpTrace(ctx context.Context, trace *HttpTrace) context.Context

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

func (t *GSSAPITransport) RoundTrip(req *http.Request) (*http.Response, error)

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

func NewHandler(provider gssapi.Provider, next http.Handler, options ...HandlerOption) *Handler

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

type HttpTrace struct {
	WaitedFor100Continue bool
	Seen100Continue      bool
}

HttpTrace gathers infromation during the HTTP request/response cycle.

func GetHttpTrace

func GetHttpTrace(ctx context.Context) *HttpTrace

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

type OpportunisticFunc func(url url.URL) bool

OpportunisticFunc is a function that returns true if opportunistic authentication should be used for a given URL.

type SpnFunc

type SpnFunc func(url url.URL) string

SpnFunc is a function that returns the Service Principal Name (SPN) for a given URL.

var DefaultSpnFunc SpnFunc = defaultSpnFunc

DefaultSpnFunc is the default SPN function used for new clients.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL