github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/lib/pq/ssl_test.go (about)

     1  package pq
     2  
     3  // This file contains SSL tests
     4  
     5  import (
     6  	_ "crypto/sha256"
     7  	"crypto/x509"
     8  	"database/sql"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  )
    14  
    15  func maybeSkipSSLTests(t *testing.T) {
    16  	// Require some special variables for testing certificates
    17  	if os.Getenv("PQSSLCERTTEST_PATH") == "" {
    18  		t.Skip("PQSSLCERTTEST_PATH not set, skipping SSL tests")
    19  	}
    20  
    21  	value := os.Getenv("PQGOSSLTESTS")
    22  	if value == "" || value == "0" {
    23  		t.Skip("PQGOSSLTESTS not enabled, skipping SSL tests")
    24  	} else if value != "1" {
    25  		t.Fatalf("unexpected value %q for PQGOSSLTESTS", value)
    26  	}
    27  }
    28  
    29  func openSSLConn(t *testing.T, conninfo string) (*sql.DB, error) {
    30  	db, err := openTestConnConninfo(conninfo)
    31  	if err != nil {
    32  		// should never fail
    33  		t.Fatal(err)
    34  	}
    35  	// Do something with the connection to see whether it's working or not.
    36  	tx, err := db.Begin()
    37  	if err == nil {
    38  		return db, tx.Rollback()
    39  	}
    40  	_ = db.Close()
    41  	return nil, err
    42  }
    43  
    44  func checkSSLSetup(t *testing.T, conninfo string) {
    45  	db, err := openSSLConn(t, conninfo)
    46  	if err == nil {
    47  		db.Close()
    48  		t.Fatalf("expected error with conninfo=%q", conninfo)
    49  	}
    50  }
    51  
    52  // Connect over SSL and run a simple query to test the basics
    53  func TestSSLConnection(t *testing.T) {
    54  	maybeSkipSSLTests(t)
    55  	// Environment sanity check: should fail without SSL
    56  	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
    57  
    58  	db, err := openSSLConn(t, "sslmode=require user=pqgossltest")
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	rows, err := db.Query("SELECT 1")
    63  	if err != nil {
    64  		t.Fatal(err)
    65  	}
    66  	rows.Close()
    67  }
    68  
    69  // Test sslmode=verify-full
    70  func TestSSLVerifyFull(t *testing.T) {
    71  	maybeSkipSSLTests(t)
    72  	// Environment sanity check: should fail without SSL
    73  	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
    74  
    75  	// Not OK according to the system CA
    76  	_, err := openSSLConn(t, "host=postgres sslmode=verify-full user=pqgossltest")
    77  	if err == nil {
    78  		t.Fatal("expected error")
    79  	}
    80  	_, ok := err.(x509.UnknownAuthorityError)
    81  	if !ok {
    82  		t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
    83  	}
    84  
    85  	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
    86  	rootCert := "sslrootcert=" + rootCertPath + " "
    87  	// No match on Common Name
    88  	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-full user=pqgossltest")
    89  	if err == nil {
    90  		t.Fatal("expected error")
    91  	}
    92  	_, ok = err.(x509.HostnameError)
    93  	if !ok {
    94  		t.Fatalf("expected x509.HostnameError, got %#+v", err)
    95  	}
    96  	// OK
    97  	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-full user=pqgossltest")
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  }
   102  
   103  // Test sslmode=verify-ca
   104  func TestSSLVerifyCA(t *testing.T) {
   105  	maybeSkipSSLTests(t)
   106  	// Environment sanity check: should fail without SSL
   107  	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
   108  
   109  	// Not OK according to the system CA
   110  	_, err := openSSLConn(t, "host=postgres sslmode=verify-ca user=pqgossltest")
   111  	if err == nil {
   112  		t.Fatal("expected error")
   113  	}
   114  	_, ok := err.(x509.UnknownAuthorityError)
   115  	if !ok {
   116  		t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
   117  	}
   118  
   119  	rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
   120  	rootCert := "sslrootcert=" + rootCertPath + " "
   121  	// No match on Common Name, but that's OK
   122  	_, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-ca user=pqgossltest")
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	// Everything OK
   127  	_, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-ca user=pqgossltest")
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  }
   132  
   133  func getCertConninfo(t *testing.T, source string) string {
   134  	var sslkey string
   135  	var sslcert string
   136  
   137  	certpath := os.Getenv("PQSSLCERTTEST_PATH")
   138  
   139  	switch source {
   140  	case "missingkey":
   141  		sslkey = "/tmp/filedoesnotexist"
   142  		sslcert = filepath.Join(certpath, "postgresql.crt")
   143  	case "missingcert":
   144  		sslkey = filepath.Join(certpath, "postgresql.key")
   145  		sslcert = "/tmp/filedoesnotexist"
   146  	case "certtwice":
   147  		sslkey = filepath.Join(certpath, "postgresql.crt")
   148  		sslcert = filepath.Join(certpath, "postgresql.crt")
   149  	case "valid":
   150  		sslkey = filepath.Join(certpath, "postgresql.key")
   151  		sslcert = filepath.Join(certpath, "postgresql.crt")
   152  	default:
   153  		t.Fatalf("invalid source %q", source)
   154  	}
   155  	return fmt.Sprintf("sslmode=require user=pqgosslcert sslkey=%s sslcert=%s", sslkey, sslcert)
   156  }
   157  
   158  // Authenticate over SSL using client certificates
   159  func TestSSLClientCertificates(t *testing.T) {
   160  	maybeSkipSSLTests(t)
   161  	// Environment sanity check: should fail without SSL
   162  	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
   163  
   164  	// Should also fail without a valid certificate
   165  	db, err := openSSLConn(t, "sslmode=require user=pqgosslcert")
   166  	if err == nil {
   167  		db.Close()
   168  		t.Fatal("expected error")
   169  	}
   170  	pge, ok := err.(*Error)
   171  	if !ok {
   172  		t.Fatal("expected pq.Error")
   173  	}
   174  	if pge.Code.Name() != "invalid_authorization_specification" {
   175  		t.Fatalf("unexpected error code %q", pge.Code.Name())
   176  	}
   177  
   178  	// Should work
   179  	db, err = openSSLConn(t, getCertConninfo(t, "valid"))
   180  	if err != nil {
   181  		t.Fatal(err)
   182  	}
   183  	rows, err := db.Query("SELECT 1")
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	rows.Close()
   188  }
   189  
   190  // Test errors with ssl certificates
   191  func TestSSLClientCertificatesMissingFiles(t *testing.T) {
   192  	maybeSkipSSLTests(t)
   193  	// Environment sanity check: should fail without SSL
   194  	checkSSLSetup(t, "sslmode=disable user=pqgossltest")
   195  
   196  	// Key missing, should fail
   197  	_, err := openSSLConn(t, getCertConninfo(t, "missingkey"))
   198  	if err == nil {
   199  		t.Fatal("expected error")
   200  	}
   201  	// should be a PathError
   202  	_, ok := err.(*os.PathError)
   203  	if !ok {
   204  		t.Fatalf("expected PathError, got %#+v", err)
   205  	}
   206  
   207  	// Cert missing, should fail
   208  	_, err = openSSLConn(t, getCertConninfo(t, "missingcert"))
   209  	if err == nil {
   210  		t.Fatal("expected error")
   211  	}
   212  	// should be a PathError
   213  	_, ok = err.(*os.PathError)
   214  	if !ok {
   215  		t.Fatalf("expected PathError, got %#+v", err)
   216  	}
   217  
   218  	// Key has wrong permissions, should fail
   219  	_, err = openSSLConn(t, getCertConninfo(t, "certtwice"))
   220  	if err == nil {
   221  		t.Fatal("expected error")
   222  	}
   223  	if err != ErrSSLKeyHasWorldPermissions {
   224  		t.Fatalf("expected ErrSSLKeyHasWorldPermissions, got %#+v", err)
   225  	}
   226  }