| /* |
| * |
| * Copyright 2020 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package credentials |
| |
| import ( |
| "crypto/tls" |
| "crypto/x509" |
| "encoding/pem" |
| "io/ioutil" |
| "net/url" |
| "testing" |
| |
| "google.golang.org/grpc/internal/grpctest" |
| "google.golang.org/grpc/testdata" |
| ) |
| |
| const wantURI = "spiffe://foo.bar.com/client/workload/1" |
| |
| type s struct { |
| grpctest.Tester |
| } |
| |
| func Test(t *testing.T) { |
| grpctest.RunSubTests(t, s{}) |
| } |
| |
| func (s) TestSPIFFEIDFromState(t *testing.T) { |
| tests := []struct { |
| name string |
| urls []*url.URL |
| // If we expect a SPIFFE ID to be returned. |
| wantID bool |
| }{ |
| { |
| name: "empty URIs", |
| urls: []*url.URL{}, |
| wantID: false, |
| }, |
| { |
| name: "good SPIFFE ID", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: true, |
| }, |
| { |
| name: "invalid host", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "invalid path", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "foo.bar.com", |
| Path: "", |
| RawPath: "", |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "large path", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "foo.bar.com", |
| Path: string(make([]byte, 2050)), |
| RawPath: string(make([]byte, 2050)), |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "large host", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: string(make([]byte, 256)), |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "multiple URI SANs", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| { |
| Scheme: "spiffe", |
| Host: "bar.baz.com", |
| Path: "workload/wl2", |
| RawPath: "workload/wl2", |
| }, |
| { |
| Scheme: "https", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "multiple URI SANs without SPIFFE ID", |
| urls: []*url.URL{ |
| { |
| Scheme: "https", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| { |
| Scheme: "ssh", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: false, |
| }, |
| { |
| name: "multiple URI SANs with one SPIFFE ID", |
| urls: []*url.URL{ |
| { |
| Scheme: "spiffe", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| { |
| Scheme: "https", |
| Host: "foo.bar.com", |
| Path: "workload/wl1", |
| RawPath: "workload/wl1", |
| }, |
| }, |
| wantID: false, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| state := tls.ConnectionState{PeerCertificates: []*x509.Certificate{{URIs: tt.urls}}} |
| id := SPIFFEIDFromState(state) |
| if got, want := id != nil, tt.wantID; got != want { |
| t.Errorf("want wantID = %v, but SPIFFE ID is %v", want, id) |
| } |
| }) |
| } |
| } |
| |
| func (s) TestSPIFFEIDFromCert(t *testing.T) { |
| tests := []struct { |
| name string |
| dataPath string |
| // If we expect a SPIFFE ID to be returned. |
| wantID bool |
| }{ |
| { |
| name: "good certificate with SPIFFE ID", |
| dataPath: "x509/spiffe_cert.pem", |
| wantID: true, |
| }, |
| { |
| name: "bad certificate with SPIFFE ID and another URI", |
| dataPath: "x509/multiple_uri_cert.pem", |
| wantID: false, |
| }, |
| { |
| name: "certificate without SPIFFE ID", |
| dataPath: "x509/client1_cert.pem", |
| wantID: false, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| data, err := ioutil.ReadFile(testdata.Path(tt.dataPath)) |
| if err != nil { |
| t.Fatalf("ioutil.ReadFile(%s) failed: %v", testdata.Path(tt.dataPath), err) |
| } |
| block, _ := pem.Decode(data) |
| if block == nil { |
| t.Fatalf("Failed to parse the certificate: byte block is nil") |
| } |
| cert, err := x509.ParseCertificate(block.Bytes) |
| if err != nil { |
| t.Fatalf("x509.ParseCertificate(%b) failed: %v", block.Bytes, err) |
| } |
| uri := SPIFFEIDFromCert(cert) |
| if (uri != nil) != tt.wantID { |
| t.Fatalf("wantID got and want mismatch, got %t, want %t", uri != nil, tt.wantID) |
| } |
| if uri != nil && uri.String() != wantURI { |
| t.Fatalf("SPIFFE ID not expected, got %s, want %s", uri.String(), wantURI) |
| } |
| }) |
| } |
| } |