@ -8,6 +8,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"strings"
"sync"
"testing"
"time"
@ -15,6 +16,7 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose"
"go.step.sm/crypto/randutil"
)
@ -74,6 +76,30 @@ func startCAServer(configFile string) (*CA, string, error) {
return ca , caURL , nil
}
func mTLSMiddleware ( next http . Handler , nonAuthenticatedPaths ... string ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
if r . URL . Path == "/version" {
api . JSON ( w , api . VersionResponse {
Version : "test" ,
RequireClientAuthentication : true ,
} )
return
}
for _ , s := range nonAuthenticatedPaths {
if strings . HasPrefix ( r . URL . Path , s ) || strings . HasPrefix ( r . URL . Path , "/1.0" + s ) {
next . ServeHTTP ( w , r )
}
}
isMTLS := r . TLS != nil && len ( r . TLS . PeerCertificates ) > 0
if ! isMTLS {
api . WriteError ( w , errs . Unauthorized ( "missing peer certificate" ) )
} else {
next . ServeHTTP ( w , r )
}
} )
}
func generateBootstrapToken ( ca , subject , sha string ) string {
now := time . Now ( )
jwk , err := jose . ReadKey ( "testdata/secrets/ott_mariano_priv.jwk" , jose . WithPassword ( [ ] byte ( "password" ) ) )
@ -171,6 +197,15 @@ func TestBootstrapServerWithoutMTLS(t *testing.T) {
token := func ( ) string {
return generateBootstrapToken ( srv . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
mtlsServer := startCABootstrapServer ( )
next := mtlsServer . Config . Handler
mtlsServer . Config . Handler = mTLSMiddleware ( next , "/root/" , "/sign" )
defer mtlsServer . Close ( )
mtlsToken := func ( ) string {
return generateBootstrapToken ( mtlsServer . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
type args struct {
ctx context . Context
token string
@ -182,6 +217,7 @@ func TestBootstrapServerWithoutMTLS(t *testing.T) {
wantErr bool
} {
{ "ok" , args { context . Background ( ) , token ( ) , & http . Server { } } , false } ,
{ "ok mtls" , args { context . Background ( ) , mtlsToken ( ) , & http . Server { } } , false } ,
{ "fail" , args { context . Background ( ) , "bad-token" , & http . Server { } } , true } ,
{ "fail with TLSConfig" , args { context . Background ( ) , token ( ) , & http . Server { TLSConfig : & tls . Config { } } } , true } ,
}
@ -217,6 +253,15 @@ func TestBootstrapServerWithMTLS(t *testing.T) {
token := func ( ) string {
return generateBootstrapToken ( srv . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
mtlsServer := startCABootstrapServer ( )
next := mtlsServer . Config . Handler
mtlsServer . Config . Handler = mTLSMiddleware ( next , "/root/" , "/sign" )
defer mtlsServer . Close ( )
mtlsToken := func ( ) string {
return generateBootstrapToken ( mtlsServer . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
type args struct {
ctx context . Context
token string
@ -228,6 +273,7 @@ func TestBootstrapServerWithMTLS(t *testing.T) {
wantErr bool
} {
{ "ok" , args { context . Background ( ) , token ( ) , & http . Server { } } , false } ,
{ "ok mtls" , args { context . Background ( ) , mtlsToken ( ) , & http . Server { } } , false } ,
{ "fail" , args { context . Background ( ) , "bad-token" , & http . Server { } } , true } ,
{ "fail with TLSConfig" , args { context . Background ( ) , token ( ) , & http . Server { TLSConfig : & tls . Config { } } } , true } ,
}
@ -263,6 +309,15 @@ func TestBootstrapClient(t *testing.T) {
token := func ( ) string {
return generateBootstrapToken ( srv . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
mtlsServer := startCABootstrapServer ( )
next := mtlsServer . Config . Handler
mtlsServer . Config . Handler = mTLSMiddleware ( next , "/root/" , "/sign" )
defer mtlsServer . Close ( )
mtlsToken := func ( ) string {
return generateBootstrapToken ( mtlsServer . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
type args struct {
ctx context . Context
token string
@ -273,6 +328,7 @@ func TestBootstrapClient(t *testing.T) {
wantErr bool
} {
{ "ok" , args { context . Background ( ) , token ( ) } , false } ,
{ "ok mtls" , args { context . Background ( ) , mtlsToken ( ) } , false } ,
{ "fail" , args { context . Background ( ) , "bad-token" } , true } ,
}
for _ , tt := range tests {
@ -541,6 +597,15 @@ func TestBootstrapListener(t *testing.T) {
token := func ( ) string {
return generateBootstrapToken ( srv . URL , "127.0.0.1" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
mtlsServer := startCABootstrapServer ( )
next := mtlsServer . Config . Handler
mtlsServer . Config . Handler = mTLSMiddleware ( next , "/root/" , "/sign" )
defer mtlsServer . Close ( )
mtlsToken := func ( ) string {
return generateBootstrapToken ( mtlsServer . URL , "subject" , "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7" )
}
type args struct {
token string
}
@ -550,6 +615,7 @@ func TestBootstrapListener(t *testing.T) {
wantErr bool
} {
{ "ok" , args { token ( ) } , false } ,
{ "ok mtls" , args { mtlsToken ( ) } , false } ,
{ "fail" , args { "bad-token" } , true } ,
}
for _ , tt := range tests {