mirror of https://github.com/docker/docs.git
331 lines
9.3 KiB
Go
331 lines
9.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/docker/notary/server/storage"
|
|
"github.com/docker/notary/signer/client"
|
|
"github.com/docker/notary/tuf/data"
|
|
"github.com/docker/notary/tuf/signed"
|
|
"github.com/docker/notary/utils"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const (
|
|
Cert = "../../fixtures/notary-server.crt"
|
|
Key = "../../fixtures/notary-server.key"
|
|
Root = "../../fixtures/root-ca.crt"
|
|
)
|
|
|
|
// initializes a viper object with test configuration
|
|
func configure(jsonConfig string) *viper.Viper {
|
|
config := viper.New()
|
|
config.SetConfigType("json")
|
|
config.ReadConfig(bytes.NewBuffer([]byte(jsonConfig)))
|
|
return config
|
|
}
|
|
|
|
func TestGetAddrAndTLSConfigInvalidTLS(t *testing.T) {
|
|
invalids := []string{
|
|
`{"server": {
|
|
"http_addr": ":1234",
|
|
"tls_key_file": "nope"
|
|
}}`,
|
|
}
|
|
for _, configJSON := range invalids {
|
|
_, _, err := getAddrAndTLSConfig(configure(configJSON))
|
|
assert.Error(t, err)
|
|
}
|
|
}
|
|
|
|
func TestGetAddrAndTLSConfigNoHTTPAddr(t *testing.T) {
|
|
_, _, err := getAddrAndTLSConfig(configure(fmt.Sprintf(`{
|
|
"server": {
|
|
"tls_cert_file": "%s",
|
|
"tls_key_file": "%s"
|
|
}
|
|
}`, Cert, Key)))
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "http listen address required for server")
|
|
}
|
|
|
|
func TestGetAddrAndTLSConfigSuccessWithTLS(t *testing.T) {
|
|
httpAddr, tlsConf, err := getAddrAndTLSConfig(configure(fmt.Sprintf(`{
|
|
"server": {
|
|
"http_addr": ":2345",
|
|
"tls_cert_file": "%s",
|
|
"tls_key_file": "%s"
|
|
}
|
|
}`, Cert, Key)))
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ":2345", httpAddr)
|
|
assert.NotNil(t, tlsConf)
|
|
}
|
|
|
|
func TestGetAddrAndTLSConfigSuccessWithoutTLS(t *testing.T) {
|
|
httpAddr, tlsConf, err := getAddrAndTLSConfig(configure(
|
|
`{"server": {"http_addr": ":2345"}}`))
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ":2345", httpAddr)
|
|
assert.Nil(t, tlsConf)
|
|
}
|
|
|
|
// We don't support client CAs yet on notary server
|
|
func TestGetAddrAndTLSConfigSkipClientTLS(t *testing.T) {
|
|
httpAddr, tlsConf, err := getAddrAndTLSConfig(configure(fmt.Sprintf(`{
|
|
"server": {
|
|
"http_addr": ":2345",
|
|
"tls_cert_file": "%s",
|
|
"tls_key_file": "%s",
|
|
"client_ca_file": "%s"
|
|
}
|
|
}`, Cert, Key, Root)))
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ":2345", httpAddr)
|
|
assert.Nil(t, tlsConf.ClientCAs)
|
|
}
|
|
|
|
// If neither "remote" nor "local" is passed for "trust_service.type", an
|
|
// error is returned.
|
|
func TestGetInvalidTrustService(t *testing.T) {
|
|
invalids := []string{
|
|
`{"trust_service": {"type": "bruhaha", "key_algorithm": "rsa"}}`,
|
|
`{}`,
|
|
}
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
for _, config := range invalids {
|
|
_, _, err := getTrustService(configure(config),
|
|
client.NewNotarySigner, fakeRegister)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(),
|
|
"must specify either a \"local\" or \"remote\" type for trust_service")
|
|
}
|
|
// no health function ever registered
|
|
assert.Equal(t, 0, registerCalled)
|
|
}
|
|
|
|
// If a local trust service is specified, a local trust service will be used
|
|
// with an ED22519 algorithm no matter what algorithm was specified. No health
|
|
// function is configured.
|
|
func TestGetLocalTrustService(t *testing.T) {
|
|
localConfig := `{"trust_service": {"type": "local", "key_algorithm": "meh"}}`
|
|
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
trust, algo, err := getTrustService(configure(localConfig),
|
|
client.NewNotarySigner, fakeRegister)
|
|
assert.NoError(t, err)
|
|
assert.IsType(t, &signed.Ed25519{}, trust)
|
|
assert.Equal(t, data.ED25519Key, algo)
|
|
|
|
// no health function ever registered
|
|
assert.Equal(t, 0, registerCalled)
|
|
}
|
|
|
|
// Invalid key algorithms result in an error if a remote trust service was
|
|
// specified.
|
|
func TestGetTrustServiceInvalidKeyAlgorithm(t *testing.T) {
|
|
configTemplate := `
|
|
{
|
|
"trust_service": {
|
|
"type": "remote",
|
|
"hostname": "blah",
|
|
"port": "1234",
|
|
"key_algorithm": "%s"
|
|
}
|
|
}`
|
|
badKeyAlgos := []string{
|
|
fmt.Sprintf(configTemplate, ""),
|
|
fmt.Sprintf(configTemplate, data.ECDSAx509Key),
|
|
fmt.Sprintf(configTemplate, "random"),
|
|
}
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
for _, config := range badKeyAlgos {
|
|
_, _, err := getTrustService(configure(config),
|
|
client.NewNotarySigner, fakeRegister)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid key algorithm")
|
|
}
|
|
// no health function ever registered
|
|
assert.Equal(t, 0, registerCalled)
|
|
}
|
|
|
|
// template to be used for testing TLS parsing with the trust service
|
|
var trustTLSConfigTemplate = `
|
|
{
|
|
"trust_service": {
|
|
"type": "remote",
|
|
"hostname": "notary-signer",
|
|
"port": "1234",
|
|
"key_algorithm": "ecdsa",
|
|
%s
|
|
}
|
|
}`
|
|
|
|
// Client cert and Key either both have to be empty or both have to be
|
|
// provided.
|
|
func TestGetTrustServiceTLSMissingCertOrKey(t *testing.T) {
|
|
configs := []string{
|
|
fmt.Sprintf(`"tls_client_cert": "%s"`, Cert),
|
|
fmt.Sprintf(`"tls_client_key": "%s"`, Key),
|
|
}
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
for _, clientTLSConfig := range configs {
|
|
jsonConfig := fmt.Sprintf(trustTLSConfigTemplate, clientTLSConfig)
|
|
config := configure(jsonConfig)
|
|
_, _, err := getTrustService(config, client.NewNotarySigner,
|
|
fakeRegister)
|
|
assert.Error(t, err)
|
|
assert.True(t,
|
|
strings.Contains(err.Error(), "Partial TLS configuration found."))
|
|
}
|
|
// no health function ever registered
|
|
assert.Equal(t, 0, registerCalled)
|
|
}
|
|
|
|
// If no TLS configuration is provided for the host server, no TLS config will
|
|
// be set for the trust service.
|
|
func TestGetTrustServiceNoTLSConfig(t *testing.T) {
|
|
config := `{
|
|
"trust_service": {
|
|
"type": "remote",
|
|
"hostname": "notary-signer",
|
|
"port": "1234",
|
|
"key_algorithm": "ecdsa"
|
|
}
|
|
}`
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
var tlsConfig *tls.Config
|
|
var fakeNewSigner = func(_, _ string, c *tls.Config) *client.NotarySigner {
|
|
tlsConfig = c
|
|
return &client.NotarySigner{}
|
|
}
|
|
|
|
trust, algo, err := getTrustService(configure(config),
|
|
fakeNewSigner, fakeRegister)
|
|
assert.NoError(t, err)
|
|
assert.IsType(t, &client.NotarySigner{}, trust)
|
|
assert.Equal(t, "ecdsa", algo)
|
|
assert.Equal(t, "notary-signer", tlsConfig.ServerName)
|
|
assert.Nil(t, tlsConfig.RootCAs)
|
|
assert.Nil(t, tlsConfig.Certificates)
|
|
// health function registered
|
|
assert.Equal(t, 1, registerCalled)
|
|
}
|
|
|
|
// The rest of the functionality of getTrustService depends upon
|
|
// utils.ConfigureClientTLS, so this test just asserts that if successful,
|
|
// the correct tls.Config is returned based on all the configuration parameters
|
|
func TestGetTrustServiceTLSSuccess(t *testing.T) {
|
|
keypair, err := tls.LoadX509KeyPair(Cert, Key)
|
|
assert.NoError(t, err, "Unable to load cert and key for testing")
|
|
|
|
tlspart := fmt.Sprintf(`"tls_client_cert": "%s", "tls_client_key": "%s"`,
|
|
Cert, Key)
|
|
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
var tlsConfig *tls.Config
|
|
var fakeNewSigner = func(_, _ string, c *tls.Config) *client.NotarySigner {
|
|
tlsConfig = c
|
|
return &client.NotarySigner{}
|
|
}
|
|
|
|
trust, algo, err := getTrustService(
|
|
configure(fmt.Sprintf(trustTLSConfigTemplate, tlspart)),
|
|
fakeNewSigner, fakeRegister)
|
|
assert.NoError(t, err)
|
|
assert.IsType(t, &client.NotarySigner{}, trust)
|
|
assert.Equal(t, "ecdsa", algo)
|
|
assert.Equal(t, "notary-signer", tlsConfig.ServerName)
|
|
assert.Equal(t, []tls.Certificate{keypair}, tlsConfig.Certificates)
|
|
// health function registered
|
|
assert.Equal(t, 1, registerCalled)
|
|
}
|
|
|
|
// The rest of the functionality of getTrustService depends upon
|
|
// utils.ConfigureServerTLS, so this test just asserts that if it fails,
|
|
// the error is propagated.
|
|
func TestGetTrustServiceTLSFailure(t *testing.T) {
|
|
tlspart := fmt.Sprintf(`"tls_client_cert": "none", "tls_client_key": "%s"`,
|
|
Key)
|
|
|
|
var registerCalled = 0
|
|
var fakeRegister = func(_ string, _ func() error, _ time.Duration) {
|
|
registerCalled++
|
|
}
|
|
|
|
_, _, err := getTrustService(
|
|
configure(fmt.Sprintf(trustTLSConfigTemplate, tlspart)),
|
|
client.NewNotarySigner, fakeRegister)
|
|
|
|
assert.Error(t, err)
|
|
assert.True(t, strings.Contains(err.Error(),
|
|
"Unable to configure TLS to the trust service"))
|
|
|
|
// no health function ever registered
|
|
assert.Equal(t, 0, registerCalled)
|
|
}
|
|
|
|
// Just to ensure that errors are propagated
|
|
func TestGetStoreInvalid(t *testing.T) {
|
|
config := `{"storage": {"backend": "asdf", "db_url": "/tmp/1234"}}`
|
|
|
|
_, err := getStore(configure(config), []string{"mysql"})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestGetStoreDBStore(t *testing.T) {
|
|
tmpFile, err := ioutil.TempFile("/tmp", "sqlite3")
|
|
assert.NoError(t, err)
|
|
tmpFile.Close()
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
config := fmt.Sprintf(`{"storage": {"backend": "%s", "db_url": "%s"}}`,
|
|
utils.SqliteBackend, tmpFile.Name())
|
|
|
|
store, err := getStore(configure(config), []string{utils.SqliteBackend})
|
|
assert.NoError(t, err)
|
|
_, ok := store.(*storage.SQLStorage)
|
|
assert.True(t, ok)
|
|
}
|
|
|
|
func TestGetMemoryStore(t *testing.T) {
|
|
config := fmt.Sprintf(`{"storage": {"backend": "%s"}}`, utils.MemoryBackend)
|
|
store, err := getStore(configure(config),
|
|
[]string{utils.MySQLBackend, utils.MemoryBackend})
|
|
assert.NoError(t, err)
|
|
_, ok := store.(*storage.MemStorage)
|
|
assert.True(t, ok)
|
|
}
|