debian-forge-composer/cmd/osbuild-auth-tests/main_test.go
Ondřej Budai 19271a542b test/auth: rework the test to use the new openssl setup
Previous commits introduces a new way to generate all X.509 certificates
needed for testing. This commit reuses the same method for auth tests.

This has two benefits:

1) The new code generates certificates with Subject Alternative Name which
   means we can use it on systems with Go 1.15 (Fedora 33, RHEL 8.4).

2) The new code generates much saner certificates.
2020-11-05 13:48:48 +01:00

174 lines
5 KiB
Go

// +build integration
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"testing"
"github.com/stretchr/testify/require"
)
const trustedCADir = "/etc/osbuild-composer-test/ca"
type connectionConfig struct {
CACertFile string
ClientKeyFile string
ClientCertFile string
}
func createTLSConfig(config *connectionConfig) (*tls.Config, error) {
caCertPEM, err := ioutil.ReadFile(config.CACertFile)
if err != nil {
return nil, err
}
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(caCertPEM)
if !ok {
return nil, errors.New("failed to append root certificate")
}
cert, err := tls.LoadX509KeyPair(config.ClientCertFile, config.ClientKeyFile)
if err != nil {
return nil, err
}
return &tls.Config{
RootCAs: roots,
Certificates: []tls.Certificate{cert},
}, nil
}
func TestWorkerAPIAuth(t *testing.T) {
t.Run("certificate signed by a trusted CA", func(t *testing.T) {
cases := []struct {
caseDesc string
subj string
addext string
success bool
}{
{"valid CN 1", "/CN=worker.osbuild.org/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com,DNS:worker.osbuild.org", true},
{"valid CN 2", "/CN=localhost/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com,DNS:localhost", true},
{"invalid CN", "/CN=example.com/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com", false},
}
authority := &ca{BaseDir: trustedCADir}
for _, c := range cases {
t.Run(c.caseDesc, func(t *testing.T) {
ckp, err := authority.newCertificateKeyPair(c.subj, osbuildClientExt, c.addext)
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost:8700/api/worker/v1/status", ckp, c.success)
})
}
})
t.Run("certificate signed by an untrusted CA", func(t *testing.T) {
// generate a new CA
ca, err := newCA("/CN=untrusted.osbuild.org")
require.NoError(t, err)
defer ca.remove()
// create a new certificate and signed it with the new CA
ckp, err := ca.newCertificateKeyPair("/CN=localhost/emailAddress=osbuild@example.com", osbuildClientExt, "")
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost:8700/api/worker/v1/status", ckp, false)
})
t.Run("self-signed certificate", func(t *testing.T) {
// generate a new self-signed certificate
ckp, err := newSelfSignedCertificateKeyPair("/CN=osbuild.org")
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost:8700/api/worker/v1/status", ckp, false)
})
}
func TestKojiAPIAuth(t *testing.T) {
t.Run("certificate signed by a trusted CA", func(t *testing.T) {
cases := []struct {
caseDesc string
subj string
addext string
success bool
}{
{"valid CN and SAN 1", "/CN=client.osbuild.org/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com,DNS:client.osbuild.org", true},
{"valid CN and SAN 2", "/CN=localhost/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com,DNS:localhost", true},
{"invalid CN and SAN", "/CN=example.com/emailAddress=osbuild@example.com", "subjectAltName=DNS:example.com", false},
}
authority := &ca{BaseDir: trustedCADir}
for _, c := range cases {
t.Run(c.caseDesc, func(t *testing.T) {
ckp, err := authority.newCertificateKeyPair(c.subj, osbuildClientExt, c.addext)
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost/api/composer-koji/v1/status", ckp, c.success)
})
}
})
t.Run("certificate signed by an untrusted CA", func(t *testing.T) {
// generate a new CA
ca, err := newCA("/CN=osbuild.org")
require.NoError(t, err)
defer ca.remove()
// create a new certificate and signed it with the new CA
ckp, err := ca.newCertificateKeyPair("/CN=localhost/emailAddress=osbuild@example.com", osbuildClientExt, "subjectAltName=DNS:localhost")
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost/api/composer-koji/v1/status", ckp, false)
})
t.Run("self-signed certificate", func(t *testing.T) {
// generate a new self-signed certificate
ckp, err := newSelfSignedCertificateKeyPair("/CN=osbuild.org")
require.NoError(t, err)
defer ckp.remove()
testRoute(t, "https://localhost/api/composer-koji/v1/status", ckp, false)
})
}
func testRoute(t *testing.T, route string, ckp *certificateKeyPair, expectSuccess bool) {
tlsConfig, err := createTLSConfig(&connectionConfig{
CACertFile: "/etc/osbuild-composer/ca-crt.pem",
ClientKeyFile: ckp.key(),
ClientCertFile: ckp.certificate(),
})
require.NoError(t, err)
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.TLSClientConfig = tlsConfig
client := http.Client{Transport: transport}
response, err := client.Get(route)
if expectSuccess {
require.NoError(t, err)
var status struct {
Status string `json:"status"`
}
err := json.NewDecoder(response.Body).Decode(&status)
require.NoError(t, err)
require.Equal(t, "OK", status.Status)
} else {
require.Error(t, err)
}
}