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
 | |
| }
 |