1
0
mirror of https://github.com/ribbybibby/ssl_exporter.git synced 2024-11-24 08:22:17 +02:00
ssl_exporter/ssl_exporter_test.go

108 lines
3.5 KiB
Go

package main
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"regexp"
"strings"
"testing"
)
func TestProbeHandler(t *testing.T) {
certContent, err := ioutil.ReadFile("test/badssl.com-client.pem")
if err != nil {
t.Fatalf("Can't read test client certificate from disk")
}
keyContent, err := ioutil.ReadFile("test/badssl.com-client-key.pem")
if err != nil {
t.Fatalf("Can't read test client certificate key from disk")
}
keyBlock, _ := pem.Decode(keyContent)
keyBlockDecrypted, err := x509.DecryptPEMBlock(keyBlock, []byte("badssl.com"))
if err != nil {
t.Fatalf("Issue decrypting test client key")
}
emptyRootCAs := x509.NewCertPool()
certificate, err := tls.X509KeyPair(certContent, keyBlockDecrypted)
// Test the behaviour of various target URIs
// 'ok' denotes whether we expect a succesful https connection
cases := []struct {
uri string
ok bool
tlsConfig *tls.Config
}{
// Test against an assumed valid, reachable and functioning HTTPS address
{uri: "https://google.com", ok: true, tlsConfig: &tls.Config{}},
// Test against a HTTP address
{uri: "http://google.com", ok: false, tlsConfig: &tls.Config{}},
// Test against an expired certificate when we're rejecting invalid certs
{uri: "https://expired.badssl.com", ok: false, tlsConfig: &tls.Config{}},
// Test against an expired certificate when we're accepting invalid certs
{uri: "https://expired.badssl.com", ok: true, tlsConfig: &tls.Config{InsecureSkipVerify: true}},
// Test against a target with no protocol
{uri: "google.com", ok: false, tlsConfig: &tls.Config{}},
// Test against a string with spaces
{uri: "with spaces", ok: false, tlsConfig: &tls.Config{}},
// Test against nothing
{uri: "", ok: false, tlsConfig: &tls.Config{}},
// Test with client authentication
{uri: "https://client.badssl.com", ok: true, tlsConfig: &tls.Config{Certificates: []tls.Certificate{certificate}}},
// Test with an empty root CA bundle
{uri: "https://google.com", ok: false, tlsConfig: &tls.Config{RootCAs: emptyRootCAs}},
}
fmt.Println("Note: The error logs in these tests are expected. One of the important tests is that we return the expected body, even in the face of errors.")
for _, test := range cases {
uri := "/probe?target=" + test.uri
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
probeHandler(w, r, test.tlsConfig)
})
handler.ServeHTTP(rr, req)
// We should always return a 200, no matter what
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// Make sure we're getting the ssl_https_connect_success metric back
successString, err := regexp.MatchString("(ssl_https_connect_success [0-1])", rr.Body.String())
if err != nil {
t.Errorf("regexp against response body returned an error w/ %q", uri)
}
if !successString {
t.Errorf("can't find ssl_https_connect_success metric in response body w/ %q", uri)
}
// Make sure we're getting the result we expect from ssl_https_connect_success
ok := strings.Contains(rr.Body.String(), "ssl_https_connect_success 1")
if test.ok && !ok {
t.Errorf("expected https connection to succeed but it failed w/ %q", uri)
}
if !test.ok && ok {
t.Errorf("expected https connection to fail but it succeeded w/ %q", uri)
}
}
}