google.golang.org/grpc@v1.62.1/internal/credentials/spiffe_test.go (about) 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 }