Skip to content

Commit 64fb9bd

Browse files
committed
Expand httputil
This expands the functionality in httputil. It adds simple handlers for BasicAuth and redirecting to https This adds several autocert related mechanisms to `httputil`
1 parent c155a91 commit 64fb9bd

6 files changed

Lines changed: 126 additions & 0 deletions

File tree

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
github.com/pmezard/go-difflib v1.0.0 // indirect
1919
github.com/stretchr/testify v1.2.1
2020
go.opencensus.io v0.18.0
21+
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
2122
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
2223
google.golang.org/appengine v1.3.0 // indirect
2324
google.golang.org/grpc v1.14.0

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,22 @@ github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7
4848
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
4949
go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
5050
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
51+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
52+
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
53+
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
5154
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
5255
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
5356
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
57+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
58+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5459
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5560
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
5661
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5762
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
5863
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
64+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
65+
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
66+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5967
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
6068
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
6169
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=

httputil/autocert.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package httputil
2+
3+
import (
4+
"net/http"
5+
"time"
6+
7+
"github.com/pkg/errors"
8+
"golang.org/x/crypto/acme"
9+
"golang.org/x/crypto/acme/autocert"
10+
)
11+
12+
type AcmOpt func(*autocert.Manager) error
13+
14+
func WithLetsEncryptStaging() AcmOpt {
15+
return func(m *autocert.Manager) error {
16+
m.Client.DirectoryURL = "https://acme-staging.api.letsencrypt.org/directory"
17+
return nil
18+
}
19+
}
20+
21+
func WithEmail(e string) AcmOpt {
22+
return func(m *autocert.Manager) error {
23+
m.Email = e
24+
return nil
25+
}
26+
}
27+
28+
func WithRenewBefore(t time.Duration) AcmOpt {
29+
return func(m *autocert.Manager) error {
30+
m.RenewBefore = t
31+
return nil
32+
}
33+
}
34+
35+
func WithHttpClient(c *http.Client) AcmOpt {
36+
return func(m *autocert.Manager) error {
37+
m.Client.HTTPClient = c
38+
return nil
39+
}
40+
}
41+
42+
func NewAutocertManager(cache autocert.Cache, allowedHosts []string, opts ...AcmOpt) (*autocert.Manager, error) {
43+
m := &autocert.Manager{
44+
Prompt: autocert.AcceptTOS,
45+
HostPolicy: autocert.HostWhitelist(allowedHosts...),
46+
Cache: cache,
47+
Client: &acme.Client{},
48+
}
49+
50+
for _, opt := range opts {
51+
if err := opt(m); err != nil {
52+
return nil, errors.Wrap(err, "applying option to autocert manager")
53+
}
54+
}
55+
56+
return m, nil
57+
}

httputil/handlers.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package httputil
2+
3+
import (
4+
"crypto/subtle"
5+
"net/http"
6+
)
7+
8+
// BasicAuthMiddleware is http middleware to authenticate based on a
9+
// predefined map of usernames and passwords.
10+
func BasicAuthMiddleware(basicauthPairs map[string][]byte, next http.Handler) http.Handler {
11+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
12+
username, password, ok := r.BasicAuth()
13+
if !ok || username == "" {
14+
http.Error(w, "Unauthorized", http.StatusUnauthorized)
15+
return
16+
}
17+
18+
// username and password must match
19+
expectedPassword, ok := basicauthPairs[username]
20+
if !ok || subtle.ConstantTimeCompare([]byte(password), expectedPassword) != 1 {
21+
http.Error(w, "Unauthorized", http.StatusUnauthorized)
22+
return
23+
}
24+
25+
// handoff to the next handler
26+
next.ServeHTTP(w, r)
27+
})
28+
}
29+
30+
// RedirectToSecureHandler is a simple handler to redirect to the secure URL.
31+
func RedirectToSecureHandler() http.Handler {
32+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
33+
w.Header().Set("Connection", "close")
34+
url := r.URL
35+
url.Scheme = "https"
36+
url.Host = r.Host
37+
http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
38+
})
39+
}

httputil/httputil.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ func WithTLSConfig(cfg *tls.Config) Option {
1919
}
2020
}
2121

22+
func WithReadTimeout(t time.Duration) Option {
23+
return func(s *http.Server) {
24+
s.ReadTimeout = t
25+
}
26+
}
27+
28+
func WithWriteTimeout(t time.Duration) Option {
29+
return func(s *http.Server) {
30+
s.WriteTimeout = t
31+
}
32+
}
33+
2234
// NewServer creates an HTTP Server with pre-configured timeouts and a secure TLS Config.
2335
func NewServer(addr string, h http.Handler, opts ...Option) *http.Server {
2436
srv := http.Server{

tlsutil/tlsutil.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ func WithCertificates(certs []tls.Certificate) Option {
6161
}
6262
}
6363

64+
// WithGetCertificate sets the GetCertificate hook on
65+
// tls.Config.GetCertificate. It's the usual integration point for
66+
// autocert.
67+
func WithGetCertificate(getCertFunc func(*tls.ClientHelloInfo) (*tls.Certificate, error)) Option {
68+
return func(config *tls.Config) {
69+
config.GetCertificate = getCertFunc
70+
}
71+
}
72+
6473
// NewConfig returns a configured *tls.Config. By default, the TLS Config is set to
6574
// MinVersion of TLS 1.2 and a Modern Profile.
6675
//

0 commit comments

Comments
 (0)