...

Source file src/google.golang.org/grpc/internal/credentials/spiffe_test.go

Documentation: google.golang.org/grpc/internal/credentials

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package credentials
    20  
    21  import (
    22  	"crypto/tls"
    23  	"crypto/x509"
    24  	"encoding/pem"
    25  	"net/url"
    26  	"os"
    27  	"testing"
    28  
    29  	"google.golang.org/grpc/internal/grpctest"
    30  	"google.golang.org/grpc/testdata"
    31  )
    32  
    33  const wantURI = "spiffe://foo.bar.com/client/workload/1"
    34  
    35  type s struct {
    36  	grpctest.Tester
    37  }
    38  
    39  func Test(t *testing.T) {
    40  	grpctest.RunSubTests(t, s{})
    41  }
    42  
    43  func (s) TestSPIFFEIDFromState(t *testing.T) {
    44  	tests := []struct {
    45  		name string
    46  		urls []*url.URL
    47  		// If we expect a SPIFFE ID to be returned.
    48  		wantID bool
    49  	}{
    50  		{
    51  			name:   "empty URIs",
    52  			urls:   []*url.URL{},
    53  			wantID: false,
    54  		},
    55  		{
    56  			name: "good SPIFFE ID",
    57  			urls: []*url.URL{
    58  				{
    59  					Scheme:  "spiffe",
    60  					Host:    "foo.bar.com",
    61  					Path:    "workload/wl1",
    62  					RawPath: "workload/wl1",
    63  				},
    64  			},
    65  			wantID: true,
    66  		},
    67  		{
    68  			name: "invalid host",
    69  			urls: []*url.URL{
    70  				{
    71  					Scheme:  "spiffe",
    72  					Host:    "",
    73  					Path:    "workload/wl1",
    74  					RawPath: "workload/wl1",
    75  				},
    76  			},
    77  			wantID: false,
    78  		},
    79  		{
    80  			name: "invalid path",
    81  			urls: []*url.URL{
    82  				{
    83  					Scheme:  "spiffe",
    84  					Host:    "foo.bar.com",
    85  					Path:    "",
    86  					RawPath: "",
    87  				},
    88  			},
    89  			wantID: false,
    90  		},
    91  		{
    92  			name: "large path",
    93  			urls: []*url.URL{
    94  				{
    95  					Scheme:  "spiffe",
    96  					Host:    "foo.bar.com",
    97  					Path:    string(make([]byte, 2050)),
    98  					RawPath: string(make([]byte, 2050)),
    99  				},
   100  			},
   101  			wantID: false,
   102  		},
   103  		{
   104  			name: "large host",
   105  			urls: []*url.URL{
   106  				{
   107  					Scheme:  "spiffe",
   108  					Host:    string(make([]byte, 256)),
   109  					Path:    "workload/wl1",
   110  					RawPath: "workload/wl1",
   111  				},
   112  			},
   113  			wantID: false,
   114  		},
   115  		{
   116  			name: "multiple URI SANs",
   117  			urls: []*url.URL{
   118  				{
   119  					Scheme:  "spiffe",
   120  					Host:    "foo.bar.com",
   121  					Path:    "workload/wl1",
   122  					RawPath: "workload/wl1",
   123  				},
   124  				{
   125  					Scheme:  "spiffe",
   126  					Host:    "bar.baz.com",
   127  					Path:    "workload/wl2",
   128  					RawPath: "workload/wl2",
   129  				},
   130  				{
   131  					Scheme:  "https",
   132  					Host:    "foo.bar.com",
   133  					Path:    "workload/wl1",
   134  					RawPath: "workload/wl1",
   135  				},
   136  			},
   137  			wantID: false,
   138  		},
   139  		{
   140  			name: "multiple URI SANs without SPIFFE ID",
   141  			urls: []*url.URL{
   142  				{
   143  					Scheme:  "https",
   144  					Host:    "foo.bar.com",
   145  					Path:    "workload/wl1",
   146  					RawPath: "workload/wl1",
   147  				},
   148  				{
   149  					Scheme:  "ssh",
   150  					Host:    "foo.bar.com",
   151  					Path:    "workload/wl1",
   152  					RawPath: "workload/wl1",
   153  				},
   154  			},
   155  			wantID: false,
   156  		},
   157  		{
   158  			name: "multiple URI SANs with one SPIFFE ID",
   159  			urls: []*url.URL{
   160  				{
   161  					Scheme:  "spiffe",
   162  					Host:    "foo.bar.com",
   163  					Path:    "workload/wl1",
   164  					RawPath: "workload/wl1",
   165  				},
   166  				{
   167  					Scheme:  "https",
   168  					Host:    "foo.bar.com",
   169  					Path:    "workload/wl1",
   170  					RawPath: "workload/wl1",
   171  				},
   172  			},
   173  			wantID: false,
   174  		},
   175  	}
   176  	for _, tt := range tests {
   177  		t.Run(tt.name, func(t *testing.T) {
   178  			state := tls.ConnectionState{PeerCertificates: []*x509.Certificate{{URIs: tt.urls}}}
   179  			id := SPIFFEIDFromState(state)
   180  			if got, want := id != nil, tt.wantID; got != want {
   181  				t.Errorf("want wantID = %v, but SPIFFE ID is %v", want, id)
   182  			}
   183  		})
   184  	}
   185  }
   186  
   187  func (s) TestSPIFFEIDFromCert(t *testing.T) {
   188  	tests := []struct {
   189  		name     string
   190  		dataPath string
   191  		// If we expect a SPIFFE ID to be returned.
   192  		wantID bool
   193  	}{
   194  		{
   195  			name:     "good certificate with SPIFFE ID",
   196  			dataPath: "x509/spiffe_cert.pem",
   197  			wantID:   true,
   198  		},
   199  		{
   200  			name:     "bad certificate with SPIFFE ID and another URI",
   201  			dataPath: "x509/multiple_uri_cert.pem",
   202  			wantID:   false,
   203  		},
   204  		{
   205  			name:     "certificate without SPIFFE ID",
   206  			dataPath: "x509/client1_cert.pem",
   207  			wantID:   false,
   208  		},
   209  	}
   210  	for _, tt := range tests {
   211  		t.Run(tt.name, func(t *testing.T) {
   212  			data, err := os.ReadFile(testdata.Path(tt.dataPath))
   213  			if err != nil {
   214  				t.Fatalf("os.ReadFile(%s) failed: %v", testdata.Path(tt.dataPath), err)
   215  			}
   216  			block, _ := pem.Decode(data)
   217  			if block == nil {
   218  				t.Fatalf("Failed to parse the certificate: byte block is nil")
   219  			}
   220  			cert, err := x509.ParseCertificate(block.Bytes)
   221  			if err != nil {
   222  				t.Fatalf("x509.ParseCertificate(%b) failed: %v", block.Bytes, err)
   223  			}
   224  			uri := SPIFFEIDFromCert(cert)
   225  			if (uri != nil) != tt.wantID {
   226  				t.Fatalf("wantID got and want mismatch, got %t, want %t", uri != nil, tt.wantID)
   227  			}
   228  			if uri != nil && uri.String() != wantURI {
   229  				t.Fatalf("SPIFFE ID not expected, got %s, want %s", uri.String(), wantURI)
   230  			}
   231  		})
   232  	}
   233  }
   234  

View as plain text