2022-08-15 06:16:22 +00:00
|
|
|
package redirector
|
2022-08-06 20:20:46 +00:00
|
|
|
|
|
|
|
import (
|
2022-08-14 07:42:49 +00:00
|
|
|
"crypto/rand"
|
|
|
|
"crypto/rsa"
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"crypto/x509/pkix"
|
|
|
|
"encoding/pem"
|
|
|
|
"fmt"
|
2022-08-06 20:20:46 +00:00
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
|
|
. "github.com/onsi/gomega"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2022-08-14 07:42:49 +00:00
|
|
|
"math/big"
|
|
|
|
"net"
|
2022-08-06 20:20:46 +00:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
2022-08-14 07:42:49 +00:00
|
|
|
"time"
|
2022-08-06 20:20:46 +00:00
|
|
|
)
|
|
|
|
|
2022-08-14 07:42:49 +00:00
|
|
|
func genTestCerts(notBefore, notAfter time.Time) (*pem.Block, *pem.Block, error) {
|
|
|
|
// Create a Certificate Authority Cert
|
|
|
|
template := x509.Certificate{
|
|
|
|
SerialNumber: big.NewInt(0),
|
|
|
|
Subject: pkix.Name{CommonName: "localhost"},
|
|
|
|
SignatureAlgorithm: x509.SHA256WithRSA,
|
|
|
|
NotBefore: notBefore,
|
|
|
|
NotAfter: notAfter,
|
|
|
|
BasicConstraintsValid: true,
|
|
|
|
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
|
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment,
|
|
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
|
|
|
}
|
2022-08-06 20:20:46 +00:00
|
|
|
|
2022-08-14 07:42:49 +00:00
|
|
|
// Create a Private Key
|
|
|
|
key, err := rsa.GenerateKey(rand.Reader, 4096)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("Could not generate rsa key - %s", err)
|
|
|
|
}
|
2022-08-06 20:20:46 +00:00
|
|
|
|
2022-08-14 07:42:49 +00:00
|
|
|
// Use CA Cert to sign a CSR and create a Public Cert
|
|
|
|
csr := &key.PublicKey
|
|
|
|
cert, err := x509.CreateCertificate(rand.Reader, &template, &template, csr, key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("Could not generate certificate - %s", err)
|
|
|
|
}
|
2022-08-06 20:20:46 +00:00
|
|
|
|
2022-08-14 07:42:49 +00:00
|
|
|
// Convert keys into pem.Block
|
|
|
|
c := &pem.Block{Type: "CERTIFICATE", Bytes: cert}
|
|
|
|
k := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}
|
|
|
|
return c, k, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ = Describe("Check suite", func() {
|
|
|
|
var (
|
|
|
|
httpServer *httptest.Server
|
|
|
|
server *Server
|
|
|
|
handler http.HandlerFunc
|
2022-08-15 06:16:22 +00:00
|
|
|
r *Redirector
|
2022-08-14 07:42:49 +00:00
|
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
|
|
httpServer = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
handler(w, r)
|
|
|
|
}))
|
2022-08-15 06:16:22 +00:00
|
|
|
r = New(&Config{
|
|
|
|
RootCAs: x509.NewCertPool(),
|
|
|
|
})
|
2022-08-14 07:42:49 +00:00
|
|
|
})
|
|
|
|
AfterEach(func() {
|
|
|
|
httpServer.Close()
|
|
|
|
})
|
|
|
|
setupServer := func() {
|
|
|
|
u, err := url.Parse(httpServer.URL)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
server = &Server{
|
|
|
|
Host: u.Host,
|
|
|
|
Path: u.Path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Context("HTTP Checks", func() {
|
|
|
|
BeforeEach(func() {
|
|
|
|
httpServer.Start()
|
|
|
|
setupServer()
|
2022-08-06 20:20:46 +00:00
|
|
|
})
|
|
|
|
It("Should successfully check for connectivity", func() {
|
|
|
|
handler = func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkHttpScheme(server, "http", log.Fields{})
|
2022-08-06 20:20:46 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeTrue())
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
})
|
|
|
|
It("Should return an error when redirected to https", func() {
|
|
|
|
handler = func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Set("Location", strings.Replace(httpServer.URL, "http://", "https://", -1))
|
|
|
|
w.WriteHeader(http.StatusMovedPermanently)
|
|
|
|
}
|
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkHttpScheme(server, "http", log.Fields{})
|
2022-08-06 20:20:46 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeFalse())
|
|
|
|
Expect(err).To(Equal(ErrHttpsRedirect))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
Context("TLS Checks", func() {
|
2022-08-14 07:42:49 +00:00
|
|
|
var (
|
|
|
|
x509Cert *x509.Certificate
|
|
|
|
)
|
|
|
|
setupCerts := func(notBefore, notAfter time.Time) {
|
|
|
|
cert, key, err := genTestCerts(notBefore, notAfter)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic("Unable to generate test certs")
|
|
|
|
}
|
|
|
|
|
|
|
|
x509Cert, err = x509.ParseCertificate(cert.Bytes)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic("Unable to parse certificate from bytes: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
tlsPair, err := tls.X509KeyPair(pem.EncodeToMemory(cert), pem.EncodeToMemory(key))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic("Unable to load tls key pair: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
httpServer.TLS = &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{tlsPair},
|
|
|
|
}
|
|
|
|
|
|
|
|
httpServer.StartTLS()
|
|
|
|
setupServer()
|
|
|
|
}
|
|
|
|
Context("CA Tests", func() {
|
|
|
|
BeforeEach(func() {
|
|
|
|
setupCerts(time.Now(), time.Now().Add(24*time.Hour))
|
|
|
|
})
|
|
|
|
It("Should fail due to invalid ca", func() {
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkTLS(server, log.Fields{})
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeFalse())
|
|
|
|
Expect(err).ToNot(BeNil())
|
|
|
|
})
|
|
|
|
It("Should successfully validate certificates (valid ca, valid date/times, etc)", func() {
|
|
|
|
pool := x509.NewCertPool()
|
|
|
|
|
|
|
|
pool.AddCert(x509Cert)
|
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
r.config.RootCAs = pool
|
2022-08-14 07:42:49 +00:00
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkTLS(server, log.Fields{})
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeFalse())
|
|
|
|
Expect(err).ToNot(BeNil())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
Context("Expiration tests", func() {
|
|
|
|
It("Should fail due to not yet valid certificate", func() {
|
|
|
|
setupCerts(time.Now().Add(5*time.Hour), time.Now().Add(10*time.Hour))
|
|
|
|
|
|
|
|
// Trust our certs
|
|
|
|
pool := x509.NewCertPool()
|
|
|
|
|
|
|
|
pool.AddCert(x509Cert)
|
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
r.config.RootCAs = pool
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
// Check TLS
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkTLS(server, log.Fields{})
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeFalse())
|
|
|
|
Expect(err).ToNot(BeNil())
|
|
|
|
})
|
|
|
|
It("Should fail due to expired certificate", func() {
|
|
|
|
setupCerts(time.Now().Add(-10*time.Hour), time.Now().Add(-5*time.Hour))
|
|
|
|
|
|
|
|
// Trust our certs
|
|
|
|
pool := x509.NewCertPool()
|
|
|
|
|
|
|
|
pool.AddCert(x509Cert)
|
|
|
|
|
2022-08-15 06:16:22 +00:00
|
|
|
r.config.RootCAs = pool
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
// Check TLS
|
2022-08-15 06:16:22 +00:00
|
|
|
res, err := r.checkTLS(server, log.Fields{})
|
2022-08-14 07:42:49 +00:00
|
|
|
|
|
|
|
Expect(res).To(BeFalse())
|
|
|
|
Expect(err).ToNot(BeNil())
|
|
|
|
})
|
|
|
|
})
|
2022-08-06 20:20:46 +00:00
|
|
|
})
|
|
|
|
})
|