grafana/pkg/setting/setting_secure_socks_proxy_test.go
Will Browne b765c21d4c
Plugins: Pass PDC file contents in requests (#84783)
* Plugins: Pass PDC file contents in requests

* go mod tidy

* undo go.mod changes

* fix linter

* fix tests

* undo unnecessary changes

* update dep

* join with comma

* update naming

* bump SDK
2024-03-22 13:52:24 +01:00

231 lines
5.5 KiB
Go

package setting
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/ini.v1"
)
func TestReadSecureSocksDSProxySettings(t *testing.T) {
t.Parallel()
tempDir := t.TempDir()
testFilePath := filepath.Join(tempDir, "test")
testFileData := "foobar"
err := os.WriteFile(testFilePath, []byte(testFileData), 0600)
require.NoError(t, err)
rootCACertFilePath := filepath.Join(tempDir, "ca.cert")
// nolint:gosec
caCertFile, err := os.Create(rootCACertFilePath)
require.NoError(t, err)
defer func() {
err = caCertFile.Close()
require.NoError(t, err)
}()
rootCaFileData := createTestRootCAFile(t, rootCACertFilePath)
require.NoError(t, err)
cases := []struct {
description string
iniFile *ini.File
expectedSettings SecureSocksDSProxySettings
expectedErr error
}{
{
description: "default values",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
`),
expectedSettings: SecureSocksDSProxySettings{
Enabled: false,
ShowUI: true,
AllowInsecure: false,
ClientCertFilePath: "",
ClientCert: "",
ClientKey: "",
ClientKeyFilePath: "",
RootCAs: []string{},
RootCAFilePaths: []string{},
ProxyAddress: "",
ServerName: "",
},
},
{
description: "one or more root ca is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
`),
expectedErr: errors.New("one or more rootCA required"),
},
{
description: "client cert is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
root_ca_cert = cert
`),
expectedErr: errors.New("client key pair required"),
},
{
description: "client key is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
root_ca_cert = cert1
client_cert = cert2
`),
expectedErr: errors.New("client key pair required"),
},
{
description: "server name is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
root_ca_cert = cert1
client_cert = cert2
client_key = key
`),
expectedErr: errors.New("server name required"),
},
{
description: "proxy address is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
root_ca_cert = cert1
client_cert = cert2
client_key = key
server_name = name
`),
expectedErr: errors.New("proxy address required"),
},
{
description: "root ca, client cert and client key are not required in insecure more",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
server_name = name
allow_insecure = true
`),
expectedSettings: SecureSocksDSProxySettings{
Enabled: true,
ProxyAddress: "address",
ServerName: "name",
ShowUI: true,
AllowInsecure: true,
RootCAFilePaths: []string{},
RootCAs: []string{},
},
},
{
description: "custom values",
iniFile: mustNewIniFile(fmt.Sprintf(`
[secure_socks_datasource_proxy]
enabled = true
client_cert = %s
client_key = %s
root_ca_cert = %s
proxy_address = proxy_address
server_name = server_name
show_ui = false
allow_insecure = false
`, testFilePath, testFilePath, rootCACertFilePath)),
expectedSettings: SecureSocksDSProxySettings{
Enabled: true,
ShowUI: false,
AllowInsecure: false,
ClientCert: testFileData,
ClientCertFilePath: testFilePath,
ClientKey: testFileData,
ClientKeyFilePath: testFilePath,
RootCAs: []string{rootCaFileData},
RootCAFilePaths: []string{rootCACertFilePath},
ProxyAddress: "proxy_address",
ServerName: "server_name",
},
},
}
for _, tt := range cases {
t.Run(tt.description, func(t *testing.T) {
settings, err := readSecureSocksDSProxySettings(tt.iniFile)
if tt.expectedErr != nil {
assert.Equal(t, tt.expectedErr, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expectedSettings, settings)
}
})
}
}
func createTestRootCAFile(t *testing.T, path string) string {
t.Helper()
ca := &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"Grafana Labs"},
CommonName: "Grafana",
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
require.NoError(t, err)
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
require.NoError(t, err)
// nolint:gosec
caCertFile, err := os.Create(path)
require.NoError(t, err)
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
}
err = pem.Encode(caCertFile, block)
require.NoError(t, err)
buf := new(bytes.Buffer)
err = pem.Encode(buf, block)
require.NoError(t, err)
return buf.String()
}
func mustNewIniFile(fileContents string) *ini.File {
file, err := ini.Load([]byte(fileContents))
if err != nil {
panic(fmt.Sprintf("creating ini file for test: %s", err))
}
return file
}