|
|
|
@ -1,25 +1,46 @@ |
|
|
|
|
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 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 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
@ -32,24 +53,27 @@ func TestReadSecureSocksDSProxySettings(t *testing.T) { |
|
|
|
|
[secure_socks_datasource_proxy] |
|
|
|
|
`), |
|
|
|
|
expectedSettings: SecureSocksDSProxySettings{ |
|
|
|
|
Enabled: false, |
|
|
|
|
ClientCert: "", |
|
|
|
|
ClientKey: "", |
|
|
|
|
RootCA: "", |
|
|
|
|
ProxyAddress: "", |
|
|
|
|
ServerName: "", |
|
|
|
|
ShowUI: true, |
|
|
|
|
AllowInsecure: false, |
|
|
|
|
Enabled: false, |
|
|
|
|
ShowUI: true, |
|
|
|
|
AllowInsecure: false, |
|
|
|
|
ClientCertFilePath: "", |
|
|
|
|
ClientCert: "", |
|
|
|
|
ClientKey: "", |
|
|
|
|
ClientKeyFilePath: "", |
|
|
|
|
RootCAs: []string{}, |
|
|
|
|
RootCAFilePaths: []string{}, |
|
|
|
|
ProxyAddress: "", |
|
|
|
|
ServerName: "", |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
description: "root ca is required", |
|
|
|
|
description: "one or more root ca is required", |
|
|
|
|
iniFile: mustNewIniFile(` |
|
|
|
|
[secure_socks_datasource_proxy] |
|
|
|
|
enabled = true |
|
|
|
|
proxy_address = address |
|
|
|
|
`), |
|
|
|
|
expectedErr: errors.New("rootCA required"), |
|
|
|
|
expectedErr: errors.New("one or more rootCA required"), |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
description: "client cert is required", |
|
|
|
@ -106,35 +130,40 @@ server_name = name |
|
|
|
|
allow_insecure = true |
|
|
|
|
`), |
|
|
|
|
expectedSettings: SecureSocksDSProxySettings{ |
|
|
|
|
Enabled: true, |
|
|
|
|
ProxyAddress: "address", |
|
|
|
|
ServerName: "name", |
|
|
|
|
ShowUI: true, |
|
|
|
|
AllowInsecure: true, |
|
|
|
|
Enabled: true, |
|
|
|
|
ProxyAddress: "address", |
|
|
|
|
ServerName: "name", |
|
|
|
|
ShowUI: true, |
|
|
|
|
AllowInsecure: true, |
|
|
|
|
RootCAFilePaths: []string{}, |
|
|
|
|
RootCAs: []string{}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
description: "custom values", |
|
|
|
|
iniFile: mustNewIniFile(` |
|
|
|
|
iniFile: mustNewIniFile(fmt.Sprintf(` |
|
|
|
|
[secure_socks_datasource_proxy] |
|
|
|
|
enabled = true |
|
|
|
|
client_cert = cert |
|
|
|
|
client_key = key |
|
|
|
|
root_ca_cert = root_ca |
|
|
|
|
client_cert = %s |
|
|
|
|
client_key = %s |
|
|
|
|
root_ca_cert = %s |
|
|
|
|
proxy_address = proxy_address |
|
|
|
|
server_name = server_name |
|
|
|
|
show_ui = false |
|
|
|
|
allow_insecure = true |
|
|
|
|
`), |
|
|
|
|
allow_insecure = false |
|
|
|
|
`, testFilePath, testFilePath, rootCACertFilePath)), |
|
|
|
|
expectedSettings: SecureSocksDSProxySettings{ |
|
|
|
|
Enabled: true, |
|
|
|
|
ClientCert: "cert", |
|
|
|
|
ClientKey: "key", |
|
|
|
|
RootCA: "root_ca", |
|
|
|
|
ProxyAddress: "proxy_address", |
|
|
|
|
ServerName: "server_name", |
|
|
|
|
ShowUI: false, |
|
|
|
|
AllowInsecure: true, |
|
|
|
|
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", |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
@ -146,9 +175,56 @@ allow_insecure = true |
|
|
|
|
if tt.expectedErr != nil { |
|
|
|
|
assert.Equal(t, tt.expectedErr, err) |
|
|
|
|
} else { |
|
|
|
|
assert.Equal(t, tt.expectedSettings, settings) |
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|