mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			231 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			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
 | 
						|
}
 |