k8s.io/apiserver@v0.31.1/pkg/authentication/request/x509/x509_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package x509
    18  
    19  import (
    20  	"crypto/tls"
    21  	"crypto/x509"
    22  	"encoding/pem"
    23  	"errors"
    24  	"io/ioutil"
    25  	"net/http"
    26  	"reflect"
    27  	"sort"
    28  	"testing"
    29  	"time"
    30  
    31  	"k8s.io/apimachinery/pkg/util/sets"
    32  	"k8s.io/apiserver/pkg/authentication/authenticator"
    33  	"k8s.io/apiserver/pkg/authentication/user"
    34  )
    35  
    36  const (
    37  
    38  	/*
    39  
    40  	   > rootCACert
    41  
    42  	   openssl genrsa -out root.key 1024 && \
    43  	   openssl rsa -in ./root.key -outform PEM -pubout -out ./root.pub && \
    44  	   CONFIG="[ v3_req ]\n" && \
    45  	   CONFIG="${CONFIG}subjectKeyIdentifier=hash\n" && \
    46  	   CONFIG="${CONFIG}authorityKeyIdentifier=keyid:always,issuer\n" && \
    47  	   CONFIG="${CONFIG}basicConstraints=CA:TRUE\n" && \
    48  	   CONFIG="${CONFIG}keyUsage=keyCertSign,cRLSign\n" && \
    49  	   openssl req -new -x509 -days 36500 \
    50  	   	-sha1 -key root.key \
    51  	   	-out root.crt \
    52  	   	-subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=ROOT CA" \
    53  	   	-config <(printf "${CONFIG}") \
    54  	   	-extensions v3_req \
    55  	   	&& \
    56  	   openssl x509 -in root.crt -text
    57  
    58  
    59  	   > output
    60  
    61  	   Certificate:
    62  	       Data:
    63  	           Version: 3 (0x2)
    64  	           Serial Number:
    65  	               2d:73:1a:2e:d7:8b:89:20:83:9c:42:9a:6e:f7:f5:f6:a1:ec:af:8c
    66  	           Signature Algorithm: sha1WithRSAEncryption
    67  	           Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA
    68  	           Validity
    69  	               Not Before: May  2 05:43:51 2024 GMT
    70  	               Not After : Apr  8 05:43:51 2124 GMT
    71  	           Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA
    72  	           Subject Public Key Info:
    73  	               Public Key Algorithm: rsaEncryption
    74  	                   Public-Key: (1024 bit)
    75  	                   Modulus:
    76  	                       00:a8:c3:dc:de:1a:f6:3e:95:97:2a:d5:bf:8b:72:
    77  	                       93:06:85:72:4b:36:2a:d9:63:a8:9c:fb:80:3e:9b:
    78  	                       2f:84:c6:57:d2:ff:33:13:bf:32:e9:90:66:db:0a:
    79  	                       9a:05:c1:e3:c1:09:bb:25:75:b2:d7:fc:9c:09:86:
    80  	                       80:15:b0:6c:67:c5:1a:e9:76:01:32:40:22:58:ec:
    81  	                       4e:a1:b7:c5:05:01:49:55:d8:4f:4b:88:1d:bf:66:
    82  	                       d3:de:58:4a:e7:26:b6:bf:af:33:d8:57:42:f1:bc:
    83  	                       34:67:44:88:b4:31:f6:4a:4a:b3:1e:c2:ca:6b:4b:
    84  	                       2e:5a:32:23:9b:1b:3f:97:35
    85  	                   Exponent: 65537 (0x10001)
    86  	           X509v3 extensions:
    87  	               X509v3 Subject Key Identifier:
    88  	                   D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B
    89  	               X509v3 Authority Key Identifier:
    90  	                   D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B
    91  	               X509v3 Basic Constraints:
    92  	                   CA:TRUE
    93  	               X509v3 Key Usage:
    94  	                   Certificate Sign, CRL Sign
    95  	       Signature Algorithm: sha1WithRSAEncryption
    96  	       Signature Value:
    97  	           4a:54:07:46:71:c1:b2:a2:d3:32:e7:df:49:8c:af:87:46:ab:
    98  	           81:11:c6:c5:4b:be:0b:0c:ea:7e:5f:38:14:79:43:92:f9:bb:
    99  	           82:6f:f6:06:a6:43:19:e2:7c:52:66:36:13:6f:0f:73:16:3d:
   100  	           79:5f:f9:a6:c8:4c:18:f9:ff:20:2b:de:7f:15:e0:ab:ae:44:
   101  	           fa:65:7a:86:8a:df:d0:63:82:b1:5c:f3:f8:5c:05:97:4e:1f:
   102  	           09:d6:d9:55:e7:36:fc:08:3e:3f:66:99:68:b6:31:44:0f:63:
   103  	           20:6a:b2:81:50:39:19:d0:47:de:20:94:f0:a2:2c:eb:69:93:
   104  	           93:a3
   105  	   -----BEGIN CERTIFICATE-----
   106  	   MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF
   107  	   BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN
   108  	   eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV
   109  	   BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx
   110  	   CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0
   111  	   eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS
   112  	   T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L
   113  	   cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV
   114  	   sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0
   115  	   MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY
   116  	   6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD
   117  	   VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB
   118  	   sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9
   119  	   eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ
   120  	   aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M=
   121  	   -----END CERTIFICATE-----
   122  
   123  
   124  	*/
   125  
   126  	rootCACert = `-----BEGIN CERTIFICATE-----
   127  MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF
   128  BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN
   129  eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV
   130  BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx
   131  CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0
   132  eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS
   133  T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L
   134  cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV
   135  sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0
   136  MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY
   137  6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD
   138  VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB
   139  sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9
   140  eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ
   141  aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M=
   142  -----END CERTIFICATE-----
   143  `
   144  
   145  	/*
   146  
   147  	   > selfSignedCert
   148  
   149  	   openssl genrsa -out selfsign.key 1024 && \
   150  	   openssl req -new -x509 -days 36500 \
   151  	   	-sha1 -key selfsign.key  \
   152  	   	-out selfsign.crt \
   153  	   	-subj "/C=US/ST=My State/L=My City/O=My Org/O=My Unit/CN=self1" \
   154  	   	&& \
   155  	   openssl x509 -in selfsign.crt -text
   156  
   157  
   158  	   > output
   159  
   160  	   Certificate:
   161  	       Data:
   162  	           Version: 3 (0x2)
   163  	           Serial Number:
   164  	               72:ae:28:f9:b7:7f:16:0a:89:a7:9c:a1:a3:88:15:4b:20:eb:f5:b2
   165  	           Signature Algorithm: sha1WithRSAEncryption
   166  	           Issuer: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1
   167  	           Validity
   168  	               Not Before: May  2 00:25:12 2024 GMT
   169  	               Not After : Apr  8 00:25:12 2124 GMT
   170  	           Subject: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1
   171  	           Subject Public Key Info:
   172  	               Public Key Algorithm: rsaEncryption
   173  	                   Public-Key: (1024 bit)
   174  	                   Modulus:
   175  	                       00:94:91:e3:8a:4d:dd:f6:27:e9:71:9c:d2:f2:64:
   176  	                       b9:af:ce:05:9d:82:a2:98:a9:15:40:8b:ff:a2:5c:
   177  	                       72:53:e8:d0:af:73:c6:76:4d:c7:6a:6e:9f:5d:a7:
   178  	                       e2:f6:aa:6a:18:2b:c3:ee:3b:64:19:16:5d:94:0b:
   179  	                       f2:f7:90:43:9a:5d:ce:7e:07:4d:b9:df:be:f0:39:
   180  	                       98:a4:41:eb:d3:17:90:12:d9:bc:d7:7f:a4:66:98:
   181  	                       c3:91:17:30:5d:7b:c4:12:2b:a9:a9:48:ca:a3:14:
   182  	                       3a:36:ad:23:58:cf:88:b9:30:9a:b4:e6:8a:35:a1:
   183  	                       ce:80:02:4a:aa:24:2b:7b:79
   184  	                   Exponent: 65537 (0x10001)
   185  	           X509v3 extensions:
   186  	               X509v3 Subject Key Identifier:
   187  	                   56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16
   188  	               X509v3 Authority Key Identifier:
   189  	                   56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16
   190  	               X509v3 Basic Constraints: critical
   191  	                   CA:TRUE
   192  	       Signature Algorithm: sha1WithRSAEncryption
   193  	       Signature Value:
   194  	           5e:84:19:68:a2:f3:41:c5:f5:57:2f:1b:e5:14:4d:8c:50:ee:
   195  	           5f:f4:aa:ec:4f:6a:06:4b:af:f3:2a:14:cc:0f:7b:a1:17:de:
   196  	           cc:da:f8:fb:c3:04:c7:a7:60:98:76:5c:32:82:5c:ec:95:a0:
   197  	           51:74:12:12:c0:7a:8b:68:bc:8b:47:47:db:95:20:34:be:69:
   198  	           d2:fc:d5:d7:e7:4b:7c:e1:f3:bc:72:3c:b1:f5:d4:db:71:ad:
   199  	           d8:a7:ad:ab:91:68:c9:16:0a:e9:76:ed:87:0f:83:24:cd:ab:
   200  	           c7:a4:16:3f:c6:7c:99:18:bb:b1:12:11:a4:a5:99:af:17:11:
   201  	           e7:b1
   202  	   -----BEGIN CERTIFICATE-----
   203  	   MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF
   204  	   BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN
   205  	   eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV
   206  	   BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw
   207  	   CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx
   208  	   DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs
   209  	   ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O
   210  	   BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd
   211  	   zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw
   212  	   mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e
   213  	   lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB
   214  	   Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0
   215  	   quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV
   216  	   IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY
   217  	   u7ESEaSlma8XEeex
   218  	   -----END CERTIFICATE-----
   219  
   220  
   221  	*/
   222  
   223  	selfSignedCert = `-----BEGIN CERTIFICATE-----
   224  MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF
   225  BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN
   226  eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV
   227  BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw
   228  CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx
   229  DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs
   230  ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O
   231  BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd
   232  zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw
   233  mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e
   234  lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB
   235  Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0
   236  quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV
   237  IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY
   238  u7ESEaSlma8XEeex
   239  -----END CERTIFICATE-----
   240  `
   241  
   242  	/*
   243  
   244  	   > clientCNCert
   245  
   246  	   openssl genrsa -out client.key 1024 && \
   247  	   openssl rsa -in ./client.key -outform PEM \
   248  	   	-pubout -out ./client.pub && \
   249  	   openssl req -key ./client.key -new\
   250  	          	-sha1 -out ./client.csr \
   251  	          	-subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=client_cn" \
   252  	   	&& \
   253  	   EXTFILE="subjectKeyIdentifier=hash\n" && \
   254  	   EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \
   255  	   EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \
   256  	   EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \
   257  	   EXTFILE="${EXTFILE}extendedKeyUsage=clientAuth\n" && \
   258  	   openssl  x509 -req -days 36500 \
   259  	   	-in ./client.csr \
   260  	   	-extfile <(printf "${EXTFILE}") \
   261  	   	-CA ./root.crt \
   262  	   	-CAkey ./root.key \
   263  	   	-set_serial 1 \
   264  	          	-sha256 \
   265  	   	-out ./client.crt \
   266  	   	&& \
   267  	   openssl x509 -in client.crt -text
   268  
   269  	   > output
   270  
   271  	   is below
   272  
   273  	*/
   274  
   275  	clientCNCert = `Certificate:
   276      Data:
   277          Version: 3 (0x2)
   278          Serial Number: 1 (0x1)
   279          Signature Algorithm: sha256WithRSAEncryption
   280          Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA
   281          Validity
   282              Not Before: May  2 05:46:24 2024 GMT
   283              Not After : Apr  8 05:46:24 2124 GMT
   284          Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = client_cn
   285          Subject Public Key Info:
   286              Public Key Algorithm: rsaEncryption
   287                  Public-Key: (1024 bit)
   288                  Modulus:
   289                      00:bd:3f:2d:d1:86:73:6d:b5:09:9c:ff:42:fb:27:
   290                      8e:07:69:a3:b6:d1:c7:72:d1:de:98:14:a5:61:9b:
   291                      83:03:1d:da:54:d1:d4:0d:7f:de:98:2e:cc:db:6f:
   292                      e4:19:c7:41:43:59:ff:34:7b:82:06:80:01:ab:79:
   293                      b3:40:d3:45:1f:52:2d:10:f9:55:40:a7:7a:61:f7:
   294                      fd:9c:41:eb:d1:ec:7e:30:ca:1a:fa:0e:9e:0f:1e:
   295                      50:93:9a:ca:55:ea:64:80:6e:bb:49:7d:12:15:d8:
   296                      6f:a8:aa:3f:b9:10:24:6f:72:22:e9:4f:f3:a4:29:
   297                      1e:4e:71:a6:82:af:39:78:a9
   298                  Exponent: 65537 (0x10001)
   299          X509v3 extensions:
   300              X509v3 Subject Key Identifier: 
   301                  FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F
   302              X509v3 Authority Key Identifier: 
   303                  D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B
   304              X509v3 Basic Constraints: 
   305                  CA:FALSE
   306              X509v3 Subject Alternative Name: 
   307                  <EMPTY>
   308  
   309              X509v3 Extended Key Usage: 
   310                  TLS Web Client Authentication
   311      Signature Algorithm: sha256WithRSAEncryption
   312      Signature Value:
   313          6b:24:0f:2f:81:46:32:c4:c1:57:09:cd:64:6d:9f:50:ee:29:
   314          4d:a7:14:d0:a0:0c:ea:a6:dc:e5:15:52:9a:42:08:eb:a2:91:
   315          3c:ce:94:0e:f0:82:bc:fd:d7:23:d1:ad:d1:98:07:94:05:fa:
   316          ca:37:45:d7:f0:7d:aa:d2:ec:94:2b:8b:03:85:00:fb:af:1d:
   317          35:28:53:a8:1d:f8:44:e1:ea:48:3f:a4:2a:46:3b:f6:19:bf:
   318          30:df:b2:0e:8d:79:b0:0a:f5:34:c7:8a:6d:bf:58:39:9d:5d:
   319          a1:f5:35:a0:54:87:98:c6:5d:bf:ea:4e:46:f9:47:6d:d7:e6:
   320          5a:f3
   321  -----BEGIN CERTIFICATE-----
   322  MIICtTCCAh6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER
   323  MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15
   324  IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1
   325  MDIwNTQ2MjRaGA8yMTI0MDQwODA1NDYyNFowaTELMAkGA1UEBhMCVVMxETAPBgNV
   326  BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx
   327  EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCWNsaWVudF9jbjCBnzANBgkqhkiG
   328  9w0BAQEFAAOBjQAwgYkCgYEAvT8t0YZzbbUJnP9C+yeOB2mjttHHctHemBSlYZuD
   329  Ax3aVNHUDX/emC7M22/kGcdBQ1n/NHuCBoABq3mzQNNFH1ItEPlVQKd6Yff9nEHr
   330  0ex+MMoa+g6eDx5Qk5rKVepkgG67SX0SFdhvqKo/uRAkb3Ii6U/zpCkeTnGmgq85
   331  eKkCAwEAAaNtMGswHQYDVR0OBBYEFPt31tCEqBDf+k6k4PEqu7SA/U8/MB8GA1Ud
   332  IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw
   333  ADATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQBrJA8vgUYy
   334  xMFXCc1kbZ9Q7ilNpxTQoAzqptzlFVKaQgjropE8zpQO8IK8/dcj0a3RmAeUBfrK
   335  N0XX8H2q0uyUK4sDhQD7rx01KFOoHfhE4epIP6QqRjv2Gb8w37IOjXmwCvU0x4pt
   336  v1g5nV2h9TWgVIeYxl2/6k5G+Udt1+Za8w==
   337  -----END CERTIFICATE-----`
   338  
   339  	/*
   340  
   341  	   > serverCert
   342  
   343  	   openssl genrsa -out server.key 1024 && \
   344  	   openssl rsa -in ./server.key -outform PEM \
   345  	   	-pubout -out ./server.pub && \
   346  	   openssl req -key ./server.key -new\
   347  	          	-sha1 -out ./server.csr \
   348  	          	-subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=127.0.0.1" \
   349  	   	&& \
   350  	   EXTFILE="subjectKeyIdentifier=hash\n" && \
   351  	   EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \
   352  	   EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \
   353  	   EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \
   354  	   EXTFILE="${EXTFILE}extendedKeyUsage=serverAuth\n" && \
   355  	   openssl  x509 -req -days 36500 \
   356  	   	-in ./server.csr \
   357  	   	-extfile <(printf "${EXTFILE}") \
   358  	   	-CA ./root.crt \
   359  	   	-CAkey ./root.key \
   360  	   	-set_serial 7 \
   361  	          	-sha256 \
   362  	   	-out ./server.crt \
   363  	   	&& \
   364  	   openssl x509 -in server.crt -text
   365  
   366  	   > output
   367  
   368  	   is below
   369  
   370  	*/
   371  
   372  	serverCert = `Certificate:
   373      Data:
   374          Version: 3 (0x2)
   375          Serial Number: 7 (0x7)
   376          Signature Algorithm: sha256WithRSAEncryption
   377          Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA
   378          Validity
   379              Not Before: May  2 05:47:31 2024 GMT
   380              Not After : Apr  8 05:47:31 2124 GMT
   381          Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = 127.0.0.1
   382          Subject Public Key Info:
   383              Public Key Algorithm: rsaEncryption
   384                  Public-Key: (1024 bit)
   385                  Modulus:
   386                      00:9d:1f:c3:9e:ac:51:92:27:df:2a:3a:48:b7:59:
   387                      40:23:a5:c3:a1:61:71:7a:00:df:d5:8b:a2:8a:7c:
   388                      54:f0:19:69:fe:ae:19:a3:e1:eb:1e:1b:39:2c:61:
   389                      fb:7b:21:10:81:b2:ef:29:94:b6:14:6f:ca:eb:4d:
   390                      f3:f6:84:93:5f:51:2c:7a:ab:9f:34:05:15:62:c4:
   391                      55:54:2e:75:b9:26:d1:0e:c5:63:41:e5:36:02:3f:
   392                      1c:5f:fc:1b:07:20:d2:1c:70:a5:a1:e8:08:1d:8f:
   393                      4c:c3:57:e0:54:72:a6:c9:24:1b:b0:fa:0d:86:f5:
   394                      26:1f:20:e5:1c:1c:c3:8f:d3
   395                  Exponent: 65537 (0x10001)
   396          X509v3 extensions:
   397              X509v3 Subject Key Identifier: 
   398                  F2:AE:B7:50:D5:02:C1:E9:8D:38:0E:76:A5:D8:24:0B:1C:DB:08:0E
   399              X509v3 Authority Key Identifier: 
   400                  D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B
   401              X509v3 Basic Constraints: 
   402                  CA:FALSE
   403              X509v3 Subject Alternative Name: 
   404                  <EMPTY>
   405  
   406              X509v3 Extended Key Usage: 
   407                  TLS Web Server Authentication
   408      Signature Algorithm: sha256WithRSAEncryption
   409      Signature Value:
   410          3f:3d:d1:5d:d5:9f:c1:ab:6e:ba:c1:c2:1b:63:1a:a8:4f:d9:
   411          df:03:13:ff:6d:a8:ed:c9:8d:19:a6:8f:a6:e2:a8:23:a0:f7:
   412          5d:5e:22:01:d1:29:9b:d0:95:75:66:46:f2:51:a7:08:1c:8c:
   413          aa:ca:4a:57:d8:ab:ed:1b:b3:77:25:58:38:1f:89:e0:a4:13:
   414          0a:f2:99:d5:3d:24:00:08:06:7e:b3:1a:b0:0b:07:33:a7:c7:
   415          ff:f8:ef:bc:7c:c9:2e:aa:3f:7a:3e:8e:8a:49:cf:a4:5a:b5:
   416          41:07:57:f1:36:f4:57:dc:6e:3f:70:38:0d:4e:71:9c:24:20:
   417          b4:36
   418  -----BEGIN CERTIFICATE-----
   419  MIICtTCCAh6gAwIBAgIBBzANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER
   420  MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15
   421  IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1
   422  MDIwNTQ3MzFaGA8yMTI0MDQwODA1NDczMVowaTELMAkGA1UEBhMCVVMxETAPBgNV
   423  BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx
   424  EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCTEyNy4wLjAuMTCBnzANBgkqhkiG
   425  9w0BAQEFAAOBjQAwgYkCgYEAnR/DnqxRkiffKjpIt1lAI6XDoWFxegDf1YuiinxU
   426  8Blp/q4Zo+HrHhs5LGH7eyEQgbLvKZS2FG/K603z9oSTX1EsequfNAUVYsRVVC51
   427  uSbRDsVjQeU2Aj8cX/wbByDSHHCloegIHY9Mw1fgVHKmySQbsPoNhvUmHyDlHBzD
   428  j9MCAwEAAaNtMGswHQYDVR0OBBYEFPKut1DVAsHpjTgOdqXYJAsc2wgOMB8GA1Ud
   429  IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw
   430  ADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOBgQA/PdFd1Z/B
   431  q266wcIbYxqoT9nfAxP/bajtyY0Zpo+m4qgjoPddXiIB0Smb0JV1ZkbyUacIHIyq
   432  ykpX2KvtG7N3JVg4H4ngpBMK8pnVPSQACAZ+sxqwCwczp8f/+O+8fMkuqj96Po6K
   433  Sc+kWrVBB1fxNvRX3G4/cDgNTnGcJCC0Ng==
   434  -----END CERTIFICATE-----
   435  `
   436  
   437  	/*
   438  	   openssl genrsa -out ca.key 4096
   439  	   openssl req -new -x509 -days 36500 \
   440  	       -sha256 -key ca.key -extensions v3_ca \
   441  	       -out ca.crt \
   442  	       -subj "/C=US/ST=My State/L=My City/O=My Org/O=My Org 1/O=My Org 2/CN=ROOT CA WITH GROUPS"
   443  	   openssl x509 -in ca.crt -text
   444  	*/
   445  
   446  	// A certificate with multiple organizations.
   447  	caWithGroups = `Certificate:
   448      Data:
   449          Version: 3 (0x2)
   450          Serial Number:
   451              bc:57:6d:0b:7c:ff:cb:52
   452      Signature Algorithm: sha256WithRSAEncryption
   453          Issuer: C=US, ST=My State, L=My City, O=My Org, O=My Org 1, O=My Org 2, CN=ROOT CA WITH GROUPS
   454          Validity
   455              Not Before: Aug 10 19:22:03 2016 GMT
   456              Not After : Jul 17 19:22:03 2116 GMT
   457          Subject: C=US, ST=My State, L=My City, O=My Org, O=My Org 1, O=My Org 2, CN=ROOT CA WITH GROUPS
   458          Subject Public Key Info:
   459              Public Key Algorithm: rsaEncryption
   460                  Public-Key: (4096 bit)
   461                  Modulus:
   462                      00:ba:3a:40:34:1a:ba:13:87:0d:c9:c7:bf:e5:8e:
   463                      6a:c7:d5:0f:8f:e3:e1:ac:9e:a5:fd:35:e1:39:52:
   464                      1d:22:77:c1:d2:3f:74:02:2e:23:c6:c1:fc:cd:30:
   465                      b4:33:e7:12:04:6f:90:27:e1:be:8e:ec:c8:dc:87:
   466                      91:da:7d:5b:8a:1f:41:fb:62:24:d0:26:98:c6:f7:
   467                      f8:ca:8a:56:15:c4:b3:5f:43:86:28:f6:4d:fc:e4:
   468                      03:52:1d:2b:25:f7:19:5c:13:c3:0e:04:91:06:f3:
   469                      29:b6:3f:8b:86:6d:b5:8e:43:2d:69:4e:60:53:5b:
   470                      75:8f:e7:d2:57:8c:db:bb:a1:0b:d7:c7:62:41:bc:
   471                      f2:87:be:66:bb:b9:bf:8b:85:97:19:98:18:50:7b:
   472                      ee:31:88:47:99:c1:04:e4:12:d2:a6:e2:bf:61:33:
   473                      82:11:79:c3:d5:39:7c:1c:15:9e:d2:61:f7:16:9f:
   474                      97:f1:39:05:8f:b9:f8:e0:5b:16:ca:da:bf:10:45:
   475                      10:0f:14:f9:67:10:66:77:05:f3:fe:21:d6:69:fb:
   476                      1e:dc:fd:f7:97:40:db:0d:59:99:8a:9d:e4:31:a3:
   477                      b9:c2:4d:ff:85:ae:ea:da:18:d8:c7:a5:b7:ea:f3:
   478                      a8:38:a5:44:1f:3b:23:71:fc:4c:5b:bd:36:6f:e0:
   479                      28:6d:f3:be:e8:c9:74:64:af:89:54:b3:12:c8:2d:
   480                      27:2d:1c:22:23:81:bd:69:b7:8b:76:63:e1:bf:80:
   481                      a1:ba:d6:c6:fc:aa:37:2e:44:94:4b:4c:3f:c4:f2:
   482                      c3:f8:25:54:ab:1f:0f:4c:19:2f:9c:b6:46:09:db:
   483                      26:52:b4:03:0a:35:75:53:94:33:5d:22:29:48:4a:
   484                      61:9c:d0:5a:6d:91:f5:18:bb:93:99:30:02:5c:6d:
   485                      7c:3f:4d:5a:ea:6f:ee:f7:7a:f9:07:9d:fe:e0:6f:
   486                      75:02:4a:ef:1e:25:c2:d5:8d:2c:57:a2:95:a7:df:
   487                      37:4f:32:60:94:09:85:4d:a7:67:05:e9:29:db:45:
   488                      a8:89:ec:1e:e9:3a:49:92:23:17:5b:4a:9c:b8:0d:
   489                      6f:2a:54:ba:47:45:f8:d3:34:30:e8:db:48:6d:c7:
   490                      82:08:01:d5:93:6a:08:7c:4b:43:78:04:df:57:b7:
   491                      fe:e3:d7:4c:ec:9c:dc:2d:0b:8c:e4:6f:aa:e2:30:
   492                      66:74:16:10:b9:44:c9:1e:73:53:86:25:25:cc:60:
   493                      3a:94:79:18:f1:c9:31:b0:e1:ca:b9:21:44:75:0a:
   494                      6c:e4:58:c1:37:ee:69:28:d1:d4:b8:78:21:64:ea:
   495                      27:d3:67:25:cf:3a:82:8d:de:27:51:b4:33:a2:85:
   496                      db:07:89
   497                  Exponent: 65537 (0x10001)
   498          X509v3 extensions:
   499              X509v3 Subject Key Identifier: 
   500                  AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4
   501              X509v3 Authority Key Identifier: 
   502                  keyid:AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4
   503  
   504              X509v3 Basic Constraints: 
   505                  CA:TRUE
   506      Signature Algorithm: sha256WithRSAEncryption
   507           1c:af:04:c9:10:f2:43:03:b6:24:2e:20:2e:47:46:4d:7f:b9:
   508           fa:1c:ea:8d:f0:30:a5:42:93:fe:e0:55:4a:b5:8b:4d:30:f4:
   509           e1:04:1f:20:ec:a1:27:ab:1f:b2:9d:da:58:2e:04:5c:b6:7c:
   510           69:8c:00:59:42:4f:cc:c7:3c:d4:f7:30:84:2a:14:8e:5d:3a:
   511           20:91:63:5c:ac:5c:e7:0c:78:fc:28:f3:f9:24:de:3d:30:e3:
   512           64:ca:5d:a6:86:30:76:5e:53:a4:99:77:a4:7a:c5:52:62:cd:
   513           f9:79:42:69:57:1b:79:25:c5:51:45:42:ed:ae:9c:bc:f2:4c:
   514           4d:9d:3a:17:73:b1:d2:94:ab:61:4a:90:fa:59:f1:96:c7:7c:
   515           26:5b:0c:75:4b:94:6f:76:ac:6c:70:8f:68:5c:e3:e7:7b:b9:
   516           38:c2:0f:f2:e3:2d:96:ec:79:fa:bf:df:33:02:f2:67:a1:19:
   517           d1:7d:ed:c4:3b:14:b8:1f:53:c5:6a:52:ad:19:2d:4c:43:19:
   518           c7:d3:14:75:7f:e7:18:40:38:79:b7:2c:ce:91:6f:cd:16:e3:
   519           d9:8f:87:be:bc:c0:c0:53:1a:93:d6:ff:a9:17:c0:d9:6f:6a:
   520           cc:0b:57:37:b8:da:30:98:4a:fc:e5:e9:dc:49:1a:33:35:f0:
   521           e9:9a:a7:a2:fd:6a:13:9e:85:df:66:a8:15:3f:94:30:4b:ca:
   522           61:72:7e:1a:b1:83:88:65:21:e8:f6:58:4a:22:48:b5:29:3d:
   523           00:6c:3e:a2:e5:bd:a5:a3:d9:5a:4d:a9:cb:2a:f8:47:ca:72:
   524           ea:9d:e1:87:e1:d1:75:5d:07:36:ba:ab:fd:7f:5f:d3:66:d0:
   525           41:86:7c:6b:1e:a7:7c:9f:dc:26:7a:37:70:54:1e:7c:b3:66:
   526           7f:f1:99:93:f4:8a:aa:81:02:e9:bf:5d:a5:90:94:82:6e:2a:
   527           a6:c8:e1:77:df:66:59:d8:6c:b1:55:a0:77:d6:53:6b:78:aa:
   528           4b:0d:fc:34:06:5c:52:4e:e6:5e:c7:94:13:19:70:e8:2b:00:
   529           6d:ea:90:b9:f4:6f:74:3f:cc:e7:1d:3e:22:ec:66:cb:84:19:
   530           7a:40:3c:7e:38:77:b4:4e:da:8c:4b:af:dc:c2:23:28:9d:60:
   531           a5:4f:5a:c8:9e:17:df:b9:9d:92:bc:d3:c0:20:12:ec:22:d4:
   532           e8:d4:97:9f:da:3c:35:a0:e9:a3:8c:d1:42:7c:c1:27:1f:8a:
   533           9b:5b:03:3d:2b:9b:df:25:b6:a8:a7:5a:48:0f:e8:1f:26:4b:
   534           0e:3c:a2:50:0a:cd:02:33:4c:e4:7a:c9:2d:b8:b8:bf:80:5a:
   535           6e:07:49:c4:c3:23:a0:2e
   536  -----BEGIN CERTIFICATE-----
   537  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
   568  PKJQCs0CM0zkesktuLi/gFpuB0nEwyOgLg==
   569  -----END CERTIFICATE-----`
   570  )
   571  
   572  func TestX509(t *testing.T) {
   573  	multilevelOpts := DefaultVerifyOptions()
   574  	multilevelOpts.Roots = x509.NewCertPool()
   575  	multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0])
   576  
   577  	testCases := map[string]struct {
   578  		Insecure bool
   579  		Certs    []*x509.Certificate
   580  
   581  		Opts x509.VerifyOptions
   582  		User UserConversion
   583  
   584  		ExpectUserName string
   585  		ExpectGroups   []string
   586  		ExpectOK       bool
   587  		ExpectErr      bool
   588  	}{
   589  		"non-tls": {
   590  			Insecure: true,
   591  
   592  			ExpectOK:  false,
   593  			ExpectErr: false,
   594  		},
   595  
   596  		"tls, no certs": {
   597  			ExpectOK:  false,
   598  			ExpectErr: false,
   599  		},
   600  
   601  		"self signed": {
   602  			Opts:  getDefaultVerifyOptions(t),
   603  			Certs: getCerts(t, selfSignedCert),
   604  			User:  CommonNameUserConversion,
   605  
   606  			ExpectErr: true,
   607  		},
   608  
   609  		"server cert": {
   610  			Opts:  getDefaultVerifyOptions(t),
   611  			Certs: getCerts(t, serverCert),
   612  			User:  CommonNameUserConversion,
   613  
   614  			ExpectErr: true,
   615  		},
   616  		"server cert allowing non-client cert usages": {
   617  			Opts:  x509.VerifyOptions{Roots: getRootCertPool(t)},
   618  			Certs: getCerts(t, serverCert),
   619  			User:  CommonNameUserConversion,
   620  
   621  			ExpectUserName: "127.0.0.1",
   622  			ExpectGroups:   []string{"My Org"},
   623  			ExpectOK:       true,
   624  			ExpectErr:      false,
   625  		},
   626  
   627  		"common name": {
   628  			Opts:  getDefaultVerifyOptions(t),
   629  			Certs: getCerts(t, clientCNCert),
   630  			User:  CommonNameUserConversion,
   631  
   632  			ExpectUserName: "client_cn",
   633  			ExpectGroups:   []string{"My Org"},
   634  			ExpectOK:       true,
   635  			ExpectErr:      false,
   636  		},
   637  		"ca with multiple organizations": {
   638  			Opts: x509.VerifyOptions{
   639  				Roots: getRootCertPoolFor(t, caWithGroups),
   640  			},
   641  			Certs: getCerts(t, caWithGroups),
   642  			User:  CommonNameUserConversion,
   643  
   644  			ExpectUserName: "ROOT CA WITH GROUPS",
   645  			ExpectGroups:   []string{"My Org", "My Org 1", "My Org 2"},
   646  			ExpectOK:       true,
   647  			ExpectErr:      false,
   648  		},
   649  
   650  		"custom conversion error": {
   651  			Opts:  getDefaultVerifyOptions(t),
   652  			Certs: getCerts(t, clientCNCert),
   653  			User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
   654  				return nil, false, errors.New("custom error")
   655  			}),
   656  
   657  			ExpectOK:  false,
   658  			ExpectErr: true,
   659  		},
   660  		"custom conversion success": {
   661  			Opts:  getDefaultVerifyOptions(t),
   662  			Certs: getCerts(t, clientCNCert),
   663  			User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) {
   664  				return &authenticator.Response{User: &user.DefaultInfo{Name: "custom"}}, true, nil
   665  			}),
   666  
   667  			ExpectUserName: "custom",
   668  			ExpectOK:       true,
   669  			ExpectErr:      false,
   670  		},
   671  
   672  		"future cert": {
   673  			Opts: x509.VerifyOptions{
   674  				CurrentTime: time.Now().Add(time.Duration(-100 * time.Hour * 24 * 365)),
   675  				Roots:       getRootCertPool(t),
   676  			},
   677  			Certs: getCerts(t, clientCNCert),
   678  			User:  CommonNameUserConversion,
   679  
   680  			ExpectOK:  false,
   681  			ExpectErr: true,
   682  		},
   683  		"expired cert": {
   684  			Opts: x509.VerifyOptions{
   685  				CurrentTime: time.Now().Add(time.Duration(100 * time.Hour * 24 * 365)),
   686  				Roots:       getRootCertPool(t),
   687  			},
   688  			Certs: getCerts(t, clientCNCert),
   689  			User:  CommonNameUserConversion,
   690  
   691  			ExpectOK:  false,
   692  			ExpectErr: true,
   693  		},
   694  
   695  		"multi-level, valid": {
   696  			Opts:  multilevelOpts,
   697  			Certs: getCertsFromFile(t, "client-valid", "intermediate"),
   698  			User:  CommonNameUserConversion,
   699  
   700  			ExpectUserName: "My Client",
   701  			ExpectOK:       true,
   702  			ExpectErr:      false,
   703  		},
   704  		"multi-level, expired": {
   705  			Opts:  multilevelOpts,
   706  			Certs: getCertsFromFile(t, "client-expired", "intermediate"),
   707  			User:  CommonNameUserConversion,
   708  
   709  			ExpectOK:  false,
   710  			ExpectErr: true,
   711  		},
   712  	}
   713  
   714  	for k, testCase := range testCases {
   715  		req, _ := http.NewRequest("GET", "/", nil)
   716  		if !testCase.Insecure {
   717  			req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs}
   718  		}
   719  
   720  		// this effectively tests the simple dynamic verify function.
   721  		a := New(testCase.Opts, testCase.User)
   722  
   723  		resp, ok, err := a.AuthenticateRequest(req)
   724  
   725  		if testCase.ExpectErr && err == nil {
   726  			t.Errorf("%s: Expected error, got none", k)
   727  			continue
   728  		}
   729  		if !testCase.ExpectErr && err != nil {
   730  			t.Errorf("%s: Got unexpected error: %v", k, err)
   731  			continue
   732  		}
   733  
   734  		if testCase.ExpectOK != ok {
   735  			t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok)
   736  			continue
   737  		}
   738  
   739  		if testCase.ExpectOK {
   740  			if testCase.ExpectUserName != resp.User.GetName() {
   741  				t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, resp.User.GetName())
   742  			}
   743  
   744  			groups := resp.User.GetGroups()
   745  			sort.Strings(testCase.ExpectGroups)
   746  			sort.Strings(groups)
   747  			if !reflect.DeepEqual(testCase.ExpectGroups, groups) {
   748  				t.Errorf("%s: Expected user.groups=%v, got %v", k, testCase.ExpectGroups, groups)
   749  			}
   750  		}
   751  	}
   752  }
   753  
   754  func TestX509Verifier(t *testing.T) {
   755  	multilevelOpts := DefaultVerifyOptions()
   756  	multilevelOpts.Roots = x509.NewCertPool()
   757  	multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0])
   758  
   759  	testCases := map[string]struct {
   760  		Insecure bool
   761  		Certs    []*x509.Certificate
   762  
   763  		Opts x509.VerifyOptions
   764  
   765  		AllowedCNs sets.String
   766  
   767  		ExpectOK  bool
   768  		ExpectErr bool
   769  	}{
   770  		"non-tls": {
   771  			Insecure: true,
   772  
   773  			ExpectOK:  false,
   774  			ExpectErr: false,
   775  		},
   776  
   777  		"tls, no certs": {
   778  			ExpectOK:  false,
   779  			ExpectErr: false,
   780  		},
   781  
   782  		"self signed": {
   783  			Opts:  getDefaultVerifyOptions(t),
   784  			Certs: getCerts(t, selfSignedCert),
   785  
   786  			ExpectErr: true,
   787  		},
   788  
   789  		"server cert disallowed": {
   790  			Opts:  getDefaultVerifyOptions(t),
   791  			Certs: getCerts(t, serverCert),
   792  
   793  			ExpectErr: true,
   794  		},
   795  		"server cert allowing non-client cert usages": {
   796  			Opts:  x509.VerifyOptions{Roots: getRootCertPool(t)},
   797  			Certs: getCerts(t, serverCert),
   798  
   799  			ExpectOK:  true,
   800  			ExpectErr: false,
   801  		},
   802  
   803  		"valid client cert": {
   804  			Opts:  getDefaultVerifyOptions(t),
   805  			Certs: getCerts(t, clientCNCert),
   806  
   807  			ExpectOK:  true,
   808  			ExpectErr: false,
   809  		},
   810  		"valid client cert with wrong CN": {
   811  			Opts:       getDefaultVerifyOptions(t),
   812  			AllowedCNs: sets.NewString("foo", "bar"),
   813  			Certs:      getCerts(t, clientCNCert),
   814  
   815  			ExpectOK:  false,
   816  			ExpectErr: true,
   817  		},
   818  		"valid client cert with right CN": {
   819  			Opts:       getDefaultVerifyOptions(t),
   820  			AllowedCNs: sets.NewString("client_cn"),
   821  			Certs:      getCerts(t, clientCNCert),
   822  
   823  			ExpectOK:  true,
   824  			ExpectErr: false,
   825  		},
   826  
   827  		"future cert": {
   828  			Opts: x509.VerifyOptions{
   829  				CurrentTime: time.Now().Add(-100 * time.Hour * 24 * 365),
   830  				Roots:       getRootCertPool(t),
   831  			},
   832  			Certs: getCerts(t, clientCNCert),
   833  
   834  			ExpectOK:  false,
   835  			ExpectErr: true,
   836  		},
   837  		"expired cert": {
   838  			Opts: x509.VerifyOptions{
   839  				CurrentTime: time.Now().Add(100 * time.Hour * 24 * 365),
   840  				Roots:       getRootCertPool(t),
   841  			},
   842  			Certs: getCerts(t, clientCNCert),
   843  
   844  			ExpectOK:  false,
   845  			ExpectErr: true,
   846  		},
   847  
   848  		"multi-level, valid": {
   849  			Opts:  multilevelOpts,
   850  			Certs: getCertsFromFile(t, "client-valid", "intermediate"),
   851  
   852  			ExpectOK:  true,
   853  			ExpectErr: false,
   854  		},
   855  		"multi-level, expired": {
   856  			Opts:  multilevelOpts,
   857  			Certs: getCertsFromFile(t, "client-expired", "intermediate"),
   858  
   859  			ExpectOK:  false,
   860  			ExpectErr: true,
   861  		},
   862  	}
   863  
   864  	for k, testCase := range testCases {
   865  		req, _ := http.NewRequest("GET", "/", nil)
   866  		if !testCase.Insecure {
   867  			req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs}
   868  		}
   869  
   870  		authCall := false
   871  		auth := authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
   872  			authCall = true
   873  			return &authenticator.Response{User: &user.DefaultInfo{Name: "innerauth"}}, true, nil
   874  		})
   875  
   876  		a := NewVerifier(testCase.Opts, auth, testCase.AllowedCNs)
   877  
   878  		resp, ok, err := a.AuthenticateRequest(req)
   879  
   880  		if testCase.ExpectErr && err == nil {
   881  			t.Errorf("%s: Expected error, got none", k)
   882  			continue
   883  		}
   884  		if !testCase.ExpectErr && err != nil {
   885  			t.Errorf("%s: Got unexpected error: %v", k, err)
   886  			continue
   887  		}
   888  
   889  		if testCase.ExpectOK != ok {
   890  			t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok)
   891  			continue
   892  		}
   893  
   894  		if testCase.ExpectOK {
   895  			if !authCall {
   896  				t.Errorf("%s: Expected inner auth called, wasn't", k)
   897  				continue
   898  			}
   899  			if "innerauth" != resp.User.GetName() {
   900  				t.Errorf("%s: Expected user.name=%v, got %v", k, "innerauth", resp.User.GetName())
   901  				continue
   902  			}
   903  		} else {
   904  			if authCall {
   905  				t.Errorf("%s: Expected inner auth not to be called, was", k)
   906  				continue
   907  			}
   908  		}
   909  	}
   910  }
   911  
   912  func getDefaultVerifyOptions(t *testing.T) x509.VerifyOptions {
   913  	options := DefaultVerifyOptions()
   914  	options.Roots = getRootCertPool(t)
   915  	return options
   916  }
   917  
   918  func getRootCertPool(t *testing.T) *x509.CertPool {
   919  	return getRootCertPoolFor(t, rootCACert)
   920  }
   921  
   922  func getRootCertPoolFor(t *testing.T, certs ...string) *x509.CertPool {
   923  	pool := x509.NewCertPool()
   924  	for _, cert := range certs {
   925  		pool.AddCert(getCert(t, cert))
   926  	}
   927  	return pool
   928  }
   929  
   930  func getCertsFromFile(t *testing.T, names ...string) []*x509.Certificate {
   931  	certs := []*x509.Certificate{}
   932  	for _, name := range names {
   933  		filename := "testdata/" + name + ".pem"
   934  		data, err := ioutil.ReadFile(filename)
   935  		if err != nil {
   936  			t.Fatalf("error reading %s: %v", filename, err)
   937  		}
   938  		certs = append(certs, getCert(t, string(data)))
   939  	}
   940  	return certs
   941  }
   942  
   943  func getCert(t *testing.T, pemData string) *x509.Certificate {
   944  	t.Helper()
   945  
   946  	pemBlock, _ := pem.Decode([]byte(pemData))
   947  	cert, err := x509.ParseCertificate(pemBlock.Bytes)
   948  	if err != nil {
   949  		t.Fatalf("Error parsing cert: %v", err)
   950  		return nil
   951  	}
   952  	return cert
   953  }
   954  
   955  func getCerts(t *testing.T, pemData ...string) []*x509.Certificate {
   956  	certs := []*x509.Certificate{}
   957  	for _, pemData := range pemData {
   958  		certs = append(certs, getCert(t, pemData))
   959  	}
   960  	return certs
   961  }
   962  
   963  func TestCertificateIdentifier(t *testing.T) {
   964  	tt := []struct {
   965  		name               string
   966  		cert               *x509.Certificate
   967  		expectedIdentifier string
   968  	}{
   969  		{
   970  			name:               "client cert",
   971  			cert:               getCert(t, clientCNCert),
   972  			expectedIdentifier: "SN=1, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B",
   973  		},
   974  		{
   975  			name: "nil serial",
   976  			cert: func() *x509.Certificate {
   977  				c := getCert(t, clientCNCert)
   978  				c.SerialNumber = nil
   979  				return c
   980  			}(),
   981  			expectedIdentifier: "SN=<nil>, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B",
   982  		},
   983  		{
   984  			name: "empty SKID",
   985  			cert: func() *x509.Certificate {
   986  				c := getCert(t, clientCNCert)
   987  				c.SubjectKeyId = nil
   988  				return c
   989  			}(),
   990  			expectedIdentifier: "SN=1, SKID=, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B",
   991  		},
   992  		{
   993  			name: "empty AKID",
   994  			cert: func() *x509.Certificate {
   995  				c := getCert(t, clientCNCert)
   996  				c.AuthorityKeyId = nil
   997  				return c
   998  			}(),
   999  			expectedIdentifier: "SN=1, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=",
  1000  		},
  1001  		{
  1002  			name:               "self-signed",
  1003  			cert:               getCert(t, selfSignedCert),
  1004  			expectedIdentifier: "SN=654708847004117259890317394342561449606220871090, SKID=56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16, AKID=56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16",
  1005  		},
  1006  	}
  1007  
  1008  	for _, tc := range tt {
  1009  		t.Run(tc.name, func(t *testing.T) {
  1010  			got := certificateIdentifier(tc.cert)
  1011  			if got != tc.expectedIdentifier {
  1012  				t.Errorf("expected %q, got %q", tc.expectedIdentifier, got)
  1013  			}
  1014  		})
  1015  	}
  1016  }