server: move AuthenticationTLS test to e2e

Signed-off-by: Stephan Renatus <srenatus@chef.io>
This commit is contained in:
Stephan Renatus
2020-10-05 10:30:42 +02:00
committed by Patrick East
parent 23b5987e94
commit 2928df76bc
11 changed files with 144 additions and 126 deletions
-126
View File
@@ -6,14 +6,10 @@ package server
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"sort"
"strings"
@@ -3097,128 +3093,6 @@ func mustUnmarshalTrace(t types.TraceV1) (trace types.TraceV1Raw) {
return trace
}
func TestAuthenticationTLS(t *testing.T) {
ctx := context.Background()
store := inmem.New()
m, err := plugins.New([]byte{}, "test", store)
if err != nil {
t.Fatal(err)
}
if err := m.Start(ctx); err != nil {
t.Fatal(err)
}
txn := storage.NewTransactionOrDie(ctx, store, storage.WriteParams)
authzPolicy := `package system.authz
import input.identity
default allow = false
allow {
identity = "CN=my-client"
}`
if err := store.UpsertPolicy(ctx, txn, "test", []byte(authzPolicy)); err != nil {
t.Fatal(err)
}
if err := store.Commit(ctx, txn); err != nil {
t.Fatal(err)
}
caCertPEM, err := ioutil.ReadFile("testdata/ca.pem")
if err != nil {
t.Fatal(err)
}
pool := x509.NewCertPool()
if ok := pool.AppendCertsFromPEM(caCertPEM); !ok {
t.Fatal("failed to parse CA cert")
}
cert, err := tls.LoadX509KeyPair("testdata/server-cert.pem", "testdata/server-key.pem")
if err != nil {
t.Fatal(err)
}
server, err := New().
WithAddresses([]string{"https://127.0.0.1:8182"}).
WithStore(store).
WithManager(m).
WithCertificate(&cert).
WithCertPool(pool).
WithAuthentication(AuthenticationTLS).
WithAuthorization(AuthorizationBasic).
Init(ctx)
if err != nil {
t.Fatal(err)
}
// Replicating some of what happens in the server's HTTPS listener
s := httptest.NewUnstartedServer(server.Handler)
s.TLS = &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: pool,
}
s.StartTLS()
defer s.Close()
endpoint := s.URL + "/v1/data/foo"
t.Run("happy path", func(t *testing.T) {
c := newClient(t, pool, "testdata/client-cert.pem", "testdata/client-key.pem")
resp, err := c.Get(endpoint)
if err != nil {
t.Fatalf("GET: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %s", resp.Status)
}
})
t.Run("authn successful, authz failed", func(t *testing.T) {
c := newClient(t, pool, "testdata/client-cert-2.pem", "testdata/client-key-2.pem")
resp, err := c.Get(endpoint)
if err != nil {
t.Fatalf("GET: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusUnauthorized {
t.Errorf("expected status 401, got %s", resp.Status)
}
})
t.Run("client trusts server, but doesn't provide client cert", func(t *testing.T) {
c := newClient(t, pool)
_, err := c.Get(endpoint)
if _, ok := err.(*url.Error); !ok {
t.Errorf("expected *url.Error, got %T: %v", err, err)
}
})
}
func newClient(t *testing.T, pool *x509.CertPool, clientKeyPair ...string) *http.Client {
t.Helper()
c := *http.DefaultClient
// Note: zero-values in http.Transport are bad settings -- they let the client
// leak connections -- but it's good enough for these tests. Don't instantiate
// http.Transport without providing non-zero values in non-test code, please.
// See https://github.com/golang/go/issues/19620 for details.
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
},
}
if len(clientKeyPair) == 2 {
clientCert, err := tls.LoadX509KeyPair(clientKeyPair[0], clientKeyPair[1])
if err != nil {
t.Fatalf("read test client cert/key: %v", err)
}
tr.TLSClientConfig.Certificates = []tls.Certificate{clientCert}
}
c.Transport = tr
return &c
}
func TestShutdown(t *testing.T) {
f := newFixture(t, func(s *Server) {
s.WithDiagnosticAddresses([]string{":8443"})
+144
View File
@@ -0,0 +1,144 @@
package tls
import (
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"testing"
"github.com/open-policy-agent/opa/server"
"github.com/open-policy-agent/opa/test/e2e"
)
var testRuntime *e2e.TestRuntime
var pool *x509.CertPool
// print error to stderr, exit 1
func fatal(err interface{}) {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
func TestMain(m *testing.M) {
flag.Parse()
caCertPEM, err := ioutil.ReadFile("testdata/ca.pem")
if err != nil {
fatal(err)
}
pool = x509.NewCertPool()
if ok := pool.AppendCertsFromPEM(caCertPEM); !ok {
fatal("failed to parse CA cert")
}
cert, err := tls.LoadX509KeyPair("testdata/server-cert.pem", "testdata/server-key.pem")
if err != nil {
fatal(err)
}
// We need the policy to be present already, otherwise authorization
// for the health endpoint is going to fail on server startup.
authzPolicy := []byte(`package system.authz
import input.identity
default allow = false
allow {
identity = "CN=my-client"
}`)
tmpfile, err := ioutil.TempFile("", "authz.*.rego")
if err != nil {
fatal(err)
}
defer os.Remove(tmpfile.Name())
if _, err := tmpfile.Write(authzPolicy); err != nil {
fatal(err)
}
if err := tmpfile.Close(); err != nil {
fatal(err)
}
testServerParams := e2e.NewAPIServerTestParams()
testServerParams.Addrs = &[]string{"https://127.0.0.1:0"}
testServerParams.CertPool = pool
testServerParams.Certificate = &cert
testServerParams.Authentication = server.AuthenticationTLS
testServerParams.Authorization = server.AuthorizationBasic
testServerParams.Paths = []string{"system.authz:" + tmpfile.Name()}
testRuntime, err = e2e.NewTestRuntime(testServerParams)
if err != nil {
fatal(err)
}
// We need a client with proper TLS setup, otherwise the health check
// that loops to determine if the server is ready will fail.
testRuntime.Client = newClient(pool, "testdata/client-cert.pem", "testdata/client-key.pem")
os.Exit(testRuntime.RunTests(m))
}
func TestAuthenticationTLS(t *testing.T) {
endpoint := testRuntime.URL() + "/v1/data/foo"
// Note: This test is redundant. When the testRuntime starts the server, it
// already queries the health endpoint using a properly authenticated, and
// authorized, http client.
t.Run("happy path", func(t *testing.T) {
c := newClient(pool, "testdata/client-cert.pem", "testdata/client-key.pem")
resp, err := c.Get(endpoint)
if err != nil {
t.Fatalf("GET: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %s", resp.Status)
}
})
t.Run("authn successful, authz failed", func(t *testing.T) {
c := newClient(pool, "testdata/client-cert-2.pem", "testdata/client-key-2.pem")
resp, err := c.Get(endpoint)
if err != nil {
t.Fatalf("GET: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusUnauthorized {
t.Errorf("expected status 401, got %s", resp.Status)
}
})
t.Run("client trusts server, but doesn't provide client cert", func(t *testing.T) {
c := newClient(pool)
_, err := c.Get(endpoint)
if _, ok := err.(*url.Error); !ok {
t.Errorf("expected *url.Error, got %T: %v", err, err)
}
})
}
func newClient(pool *x509.CertPool, clientKeyPair ...string) *http.Client {
c := *http.DefaultClient
// Note: zero-values in http.Transport are bad settings -- they let the client
// leak connections -- but it's good enough for these tests. Don't instantiate
// http.Transport without providing non-zero values in non-test code, please.
// See https://github.com/golang/go/issues/19620 for details.
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
},
}
if len(clientKeyPair) == 2 {
clientCert, err := tls.LoadX509KeyPair(clientKeyPair[0], clientKeyPair[1])
if err != nil {
panic(err)
}
tr.TLSClientConfig.Certificates = []tls.Certificate{clientCert}
}
c.Transport = tr
return &c
}