spiffe_test.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. package credentials
  19. import (
  20. "crypto/tls"
  21. "crypto/x509"
  22. "encoding/pem"
  23. "net/url"
  24. "os"
  25. "testing"
  26. "google.golang.org/grpc/internal/grpctest"
  27. "google.golang.org/grpc/testdata"
  28. )
  29. const wantURI = "spiffe://foo.bar.com/client/workload/1"
  30. type s struct {
  31. grpctest.Tester
  32. }
  33. func Test(t *testing.T) {
  34. grpctest.RunSubTests(t, s{})
  35. }
  36. func (s) TestSPIFFEIDFromState(t *testing.T) {
  37. tests := []struct {
  38. name string
  39. urls []*url.URL
  40. // If we expect a SPIFFE ID to be returned.
  41. wantID bool
  42. }{
  43. {
  44. name: "empty URIs",
  45. urls: []*url.URL{},
  46. wantID: false,
  47. },
  48. {
  49. name: "good SPIFFE ID",
  50. urls: []*url.URL{
  51. {
  52. Scheme: "spiffe",
  53. Host: "foo.bar.com",
  54. Path: "workload/wl1",
  55. RawPath: "workload/wl1",
  56. },
  57. },
  58. wantID: true,
  59. },
  60. {
  61. name: "invalid host",
  62. urls: []*url.URL{
  63. {
  64. Scheme: "spiffe",
  65. Host: "",
  66. Path: "workload/wl1",
  67. RawPath: "workload/wl1",
  68. },
  69. },
  70. wantID: false,
  71. },
  72. {
  73. name: "invalid path",
  74. urls: []*url.URL{
  75. {
  76. Scheme: "spiffe",
  77. Host: "foo.bar.com",
  78. Path: "",
  79. RawPath: "",
  80. },
  81. },
  82. wantID: false,
  83. },
  84. {
  85. name: "large path",
  86. urls: []*url.URL{
  87. {
  88. Scheme: "spiffe",
  89. Host: "foo.bar.com",
  90. Path: string(make([]byte, 2050)),
  91. RawPath: string(make([]byte, 2050)),
  92. },
  93. },
  94. wantID: false,
  95. },
  96. {
  97. name: "large host",
  98. urls: []*url.URL{
  99. {
  100. Scheme: "spiffe",
  101. Host: string(make([]byte, 256)),
  102. Path: "workload/wl1",
  103. RawPath: "workload/wl1",
  104. },
  105. },
  106. wantID: false,
  107. },
  108. {
  109. name: "multiple URI SANs",
  110. urls: []*url.URL{
  111. {
  112. Scheme: "spiffe",
  113. Host: "foo.bar.com",
  114. Path: "workload/wl1",
  115. RawPath: "workload/wl1",
  116. },
  117. {
  118. Scheme: "spiffe",
  119. Host: "bar.baz.com",
  120. Path: "workload/wl2",
  121. RawPath: "workload/wl2",
  122. },
  123. {
  124. Scheme: "https",
  125. Host: "foo.bar.com",
  126. Path: "workload/wl1",
  127. RawPath: "workload/wl1",
  128. },
  129. },
  130. wantID: false,
  131. },
  132. {
  133. name: "multiple URI SANs without SPIFFE ID",
  134. urls: []*url.URL{
  135. {
  136. Scheme: "https",
  137. Host: "foo.bar.com",
  138. Path: "workload/wl1",
  139. RawPath: "workload/wl1",
  140. },
  141. {
  142. Scheme: "ssh",
  143. Host: "foo.bar.com",
  144. Path: "workload/wl1",
  145. RawPath: "workload/wl1",
  146. },
  147. },
  148. wantID: false,
  149. },
  150. {
  151. name: "multiple URI SANs with one SPIFFE ID",
  152. urls: []*url.URL{
  153. {
  154. Scheme: "spiffe",
  155. Host: "foo.bar.com",
  156. Path: "workload/wl1",
  157. RawPath: "workload/wl1",
  158. },
  159. {
  160. Scheme: "https",
  161. Host: "foo.bar.com",
  162. Path: "workload/wl1",
  163. RawPath: "workload/wl1",
  164. },
  165. },
  166. wantID: false,
  167. },
  168. }
  169. for _, tt := range tests {
  170. t.Run(tt.name, func(t *testing.T) {
  171. state := tls.ConnectionState{PeerCertificates: []*x509.Certificate{{URIs: tt.urls}}}
  172. id := SPIFFEIDFromState(state)
  173. if got, want := id != nil, tt.wantID; got != want {
  174. t.Errorf("want wantID = %v, but SPIFFE ID is %v", want, id)
  175. }
  176. })
  177. }
  178. }
  179. func (s) TestSPIFFEIDFromCert(t *testing.T) {
  180. tests := []struct {
  181. name string
  182. dataPath string
  183. // If we expect a SPIFFE ID to be returned.
  184. wantID bool
  185. }{
  186. {
  187. name: "good certificate with SPIFFE ID",
  188. dataPath: "x509/spiffe_cert.pem",
  189. wantID: true,
  190. },
  191. {
  192. name: "bad certificate with SPIFFE ID and another URI",
  193. dataPath: "x509/multiple_uri_cert.pem",
  194. wantID: false,
  195. },
  196. {
  197. name: "certificate without SPIFFE ID",
  198. dataPath: "x509/client1_cert.pem",
  199. wantID: false,
  200. },
  201. }
  202. for _, tt := range tests {
  203. t.Run(tt.name, func(t *testing.T) {
  204. data, err := os.ReadFile(testdata.Path(tt.dataPath))
  205. if err != nil {
  206. t.Fatalf("os.ReadFile(%s) failed: %v", testdata.Path(tt.dataPath), err)
  207. }
  208. block, _ := pem.Decode(data)
  209. if block == nil {
  210. t.Fatalf("Failed to parse the certificate: byte block is nil")
  211. }
  212. cert, err := x509.ParseCertificate(block.Bytes)
  213. if err != nil {
  214. t.Fatalf("x509.ParseCertificate(%b) failed: %v", block.Bytes, err)
  215. }
  216. uri := SPIFFEIDFromCert(cert)
  217. if (uri != nil) != tt.wantID {
  218. t.Fatalf("wantID got and want mismatch, got %t, want %t", uri != nil, tt.wantID)
  219. }
  220. if uri != nil && uri.String() != wantURI {
  221. t.Fatalf("SPIFFE ID not expected, got %s, want %s", uri.String(), wantURI)
  222. }
  223. })
  224. }
  225. }