2017-07-06 17:28:13 +03:00
package integration
2015-11-21 04:59:49 +03:00
import (
2017-11-09 14:16:03 +03:00
"bytes"
2015-11-21 04:59:49 +03:00
"crypto/tls"
2017-11-09 14:16:03 +03:00
"fmt"
2015-11-21 04:59:49 +03:00
"net"
"net/http"
"net/http/httptest"
2017-06-23 16:15:07 +03:00
"os"
2015-11-21 04:59:49 +03:00
"time"
2017-11-09 14:16:03 +03:00
"github.com/BurntSushi/toml"
2017-05-17 16:22:44 +03:00
"github.com/containous/traefik/integration/try"
2017-11-09 14:16:03 +03:00
traefikTls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
2016-04-02 13:40:21 +03:00
"github.com/go-check/check"
2015-11-21 04:59:49 +03:00
checker "github.com/vdemeester/shakers"
)
// HTTPSSuite
type HTTPSSuite struct { BaseSuite }
// TestWithSNIConfigHandshake involves a client sending a SNI hostname of
// "snitest.com", which happens to match the CN of 'snitest.com.crt'. The test
// verifies that traefik presents the correct certificate.
func ( s * HTTPSSuite ) TestWithSNIConfigHandshake ( c * check . C ) {
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( "fixtures/https/https_sni.toml" ) )
defer display ( c )
2015-11-21 04:59:49 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
2017-05-17 16:22:44 +03:00
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 500 * time . Millisecond , try . BodyContains ( "Host:snitest.org" ) )
c . Assert ( err , checker . IsNil )
2015-11-21 04:59:49 +03:00
tlsConfig := & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
2016-11-09 20:43:59 +03:00
NextProtos : [ ] string { "h2" , "http/1.1" } ,
2015-11-21 04:59:49 +03:00
}
2016-01-14 00:46:44 +03:00
conn , err := tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2015-11-21 04:59:49 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
defer conn . Close ( )
err = conn . Handshake ( )
c . Assert ( err , checker . IsNil , check . Commentf ( "TLS handshake error" ) )
cs := conn . ConnectionState ( )
err = cs . PeerCertificates [ 0 ] . VerifyHostname ( "snitest.com" )
c . Assert ( err , checker . IsNil , check . Commentf ( "certificate did not match SNI servername" ) )
2016-11-09 20:43:59 +03:00
proto := conn . ConnectionState ( ) . NegotiatedProtocol
c . Assert ( proto , checker . Equals , "h2" )
2015-11-21 04:59:49 +03:00
}
// TestWithSNIConfigRoute involves a client sending HTTPS requests with
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
// that traefik routes the requests to the expected backends.
func ( s * HTTPSSuite ) TestWithSNIConfigRoute ( c * check . C ) {
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( "fixtures/https/https_sni.toml" ) )
defer display ( c )
2015-11-21 04:59:49 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
2017-05-17 16:22:44 +03:00
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 500 * time . Millisecond , try . BodyContains ( "Host:snitest.org" ) )
c . Assert ( err , checker . IsNil )
backend1 := startTestServer ( "9010" , http . StatusNoContent )
backend2 := startTestServer ( "9020" , http . StatusResetContent )
2015-11-21 04:59:49 +03:00
defer backend1 . Close ( )
defer backend2 . Close ( )
2017-05-17 16:22:44 +03:00
err = try . GetRequest ( backend1 . URL , 1 * time . Second , try . StatusCodeIs ( http . StatusNoContent ) )
c . Assert ( err , checker . IsNil )
err = try . GetRequest ( backend2 . URL , 1 * time . Second , try . StatusCodeIs ( http . StatusResetContent ) )
c . Assert ( err , checker . IsNil )
2015-11-21 04:59:49 +03:00
tr1 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
} ,
}
tr2 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.org" ,
} ,
}
client := & http . Client { Transport : tr1 }
2017-05-17 16:22:44 +03:00
req , err := http . NewRequest ( http . MethodGet , "https://127.0.0.1:4443/" , nil )
c . Assert ( err , checker . IsNil )
2015-11-21 04:59:49 +03:00
req . Host = "snitest.com"
req . Header . Set ( "Host" , "snitest.com" )
req . Header . Set ( "Accept" , "*/*" )
resp , err := client . Do ( req )
c . Assert ( err , checker . IsNil )
// Expected a 204 (from backend1)
2017-05-17 16:22:44 +03:00
c . Assert ( resp . StatusCode , checker . Equals , http . StatusNoContent )
2015-11-21 04:59:49 +03:00
client = & http . Client { Transport : tr2 }
2017-05-17 16:22:44 +03:00
req , err = http . NewRequest ( http . MethodGet , "https://127.0.0.1:4443/" , nil )
c . Assert ( err , checker . IsNil )
2015-11-21 04:59:49 +03:00
req . Host = "snitest.org"
req . Header . Set ( "Host" , "snitest.org" )
req . Header . Set ( "Accept" , "*/*" )
resp , err = client . Do ( req )
c . Assert ( err , checker . IsNil )
// Expected a 205 (from backend2)
2017-05-17 16:22:44 +03:00
c . Assert ( resp . StatusCode , checker . Equals , http . StatusResetContent )
2015-11-21 04:59:49 +03:00
}
2016-06-18 22:11:34 +03:00
// TestWithClientCertificateAuthentication
2017-11-10 12:30:04 +03:00
// The client can send a certificate signed by a CA trusted by the server but it's optional
2016-06-18 22:11:34 +03:00
func ( s * HTTPSSuite ) TestWithClientCertificateAuthentication ( c * check . C ) {
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( "fixtures/https/clientca/https_1ca1config.toml" ) )
defer display ( c )
2016-06-18 22:11:34 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
2017-05-17 16:22:44 +03:00
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 500 * time . Millisecond , try . BodyContains ( "Host:snitest.org" ) )
c . Assert ( err , checker . IsNil )
2016-06-18 22:11:34 +03:00
tlsConfig := & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
// Connection without client certificate should fail
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2017-11-10 12:30:04 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "should be allowed to connect to server" ) )
2016-06-18 22:11:34 +03:00
// Connect with client certificate signed by ca1
cert , err := tls . LoadX509KeyPair ( "fixtures/https/clientca/client1.crt" , "fixtures/https/clientca/client1.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
conn , err := tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
conn . Close ( )
2017-11-10 12:30:04 +03:00
// Connect with client certificate not signed by ca1
cert , err = tls . LoadX509KeyPair ( "fixtures/https/snitest.org.cert" , "fixtures/https/snitest.org.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
conn , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
conn . Close ( )
2016-06-18 22:11:34 +03:00
// Connect with client signed by ca2 should fail
tlsConfig = & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
cert , err = tls . LoadX509KeyPair ( "fixtures/https/clientca/client2.crt" , "fixtures/https/clientca/client2.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2017-11-10 12:30:04 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "should be allowed to connect to server" ) )
2016-06-18 22:11:34 +03:00
}
// TestWithClientCertificateAuthentication
// Use two CA:s and test that clients with client signed by either of them can connect
func ( s * HTTPSSuite ) TestWithClientCertificateAuthenticationMultipeCAs ( c * check . C ) {
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( "fixtures/https/clientca/https_2ca1config.toml" ) )
defer display ( c )
2016-06-18 22:11:34 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
2017-05-17 16:22:44 +03:00
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 500 * time . Millisecond , try . BodyContains ( "Host:snitest.org" ) )
c . Assert ( err , checker . IsNil )
2016-06-18 22:11:34 +03:00
tlsConfig := & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
// Connection without client certificate should fail
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . NotNil , check . Commentf ( "should not be allowed to connect to server" ) )
// Connect with client signed by ca1
cert , err := tls . LoadX509KeyPair ( "fixtures/https/clientca/client1.crt" , "fixtures/https/clientca/client1.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
conn , err := tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
conn . Close ( )
// Connect with client signed by ca2
tlsConfig = & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
cert , err = tls . LoadX509KeyPair ( "fixtures/https/clientca/client2.crt" , "fixtures/https/clientca/client2.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
conn , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
2017-08-18 03:18:02 +03:00
2016-06-18 22:11:34 +03:00
conn . Close ( )
// Connect with client signed by ca3 should fail
tlsConfig = & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
cert , err = tls . LoadX509KeyPair ( "fixtures/https/clientca/client3.crt" , "fixtures/https/clientca/client3.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . NotNil , check . Commentf ( "should not be allowed to connect to server" ) )
}
// TestWithClientCertificateAuthentication
// Use two CA:s in two different files and test that clients with client signed by either of them can connect
func ( s * HTTPSSuite ) TestWithClientCertificateAuthenticationMultipeCAsMultipleFiles ( c * check . C ) {
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( "fixtures/https/clientca/https_2ca2config.toml" ) )
defer display ( c )
2016-06-18 22:11:34 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
2017-05-17 16:22:44 +03:00
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 1000 * time . Millisecond , try . BodyContains ( "Host:snitest.org" ) )
c . Assert ( err , checker . IsNil )
2016-06-18 22:11:34 +03:00
tlsConfig := & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
// Connection without client certificate should fail
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . NotNil , check . Commentf ( "should not be allowed to connect to server" ) )
// Connect with client signed by ca1
cert , err := tls . LoadX509KeyPair ( "fixtures/https/clientca/client1.crt" , "fixtures/https/clientca/client1.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
conn , err := tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
conn . Close ( )
// Connect with client signed by ca2
tlsConfig = & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
cert , err = tls . LoadX509KeyPair ( "fixtures/https/clientca/client2.crt" , "fixtures/https/clientca/client2.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
conn , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to connect to server" ) )
conn . Close ( )
// Connect with client signed by ca3 should fail
tlsConfig = & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
Certificates : [ ] tls . Certificate { } ,
}
cert , err = tls . LoadX509KeyPair ( "fixtures/https/clientca/client3.crt" , "fixtures/https/clientca/client3.key" )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to load client certificate and key" ) )
tlsConfig . Certificates = append ( tlsConfig . Certificates , cert )
2017-08-18 03:18:02 +03:00
_ , err = tls . Dial ( "tcp" , "127.0.0.1:4443" , tlsConfig )
2016-06-18 22:11:34 +03:00
c . Assert ( err , checker . NotNil , check . Commentf ( "should not be allowed to connect to server" ) )
}
2017-06-23 16:15:07 +03:00
func ( s * HTTPSSuite ) TestWithRootCAsContentForHTTPSOnBackend ( c * check . C ) {
backend := httptest . NewTLSServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2017-11-20 11:40:03 +03:00
w . WriteHeader ( http . StatusOK )
2017-06-23 16:15:07 +03:00
} ) )
defer backend . Close ( )
file := s . adaptFile ( c , "fixtures/https/rootcas/https.toml" , struct { BackendHost string } { backend . URL } )
defer os . Remove ( file )
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
2017-06-23 16:15:07 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
// wait for Traefik
2017-11-09 14:16:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 1 * time . Second , try . BodyContains ( backend . URL ) )
2017-06-23 16:15:07 +03:00
c . Assert ( err , checker . IsNil )
2017-11-09 14:16:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8081/ping" , 1 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2017-06-23 16:15:07 +03:00
c . Assert ( err , checker . IsNil )
}
func ( s * HTTPSSuite ) TestWithRootCAsFileForHTTPSOnBackend ( c * check . C ) {
backend := httptest . NewTLSServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2017-11-20 11:40:03 +03:00
w . WriteHeader ( http . StatusOK )
2017-06-23 16:15:07 +03:00
} ) )
defer backend . Close ( )
file := s . adaptFile ( c , "fixtures/https/rootcas/https_with_file.toml" , struct { BackendHost string } { backend . URL } )
defer os . Remove ( file )
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
2017-06-23 16:15:07 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
// wait for Traefik
2017-11-09 14:16:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 1 * time . Second , try . BodyContains ( backend . URL ) )
2017-06-23 16:15:07 +03:00
c . Assert ( err , checker . IsNil )
2017-11-09 14:16:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8081/ping" , 1 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2017-06-23 16:15:07 +03:00
c . Assert ( err , checker . IsNil )
}
2015-11-21 04:59:49 +03:00
func startTestServer ( port string , statusCode int ) ( ts * httptest . Server ) {
handler := http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( statusCode )
} )
listener , err := net . Listen ( "tcp" , "127.0.0.1:" + port )
if err != nil {
panic ( err )
}
ts = & httptest . Server {
Listener : listener ,
Config : & http . Server { Handler : handler } ,
}
ts . Start ( )
2017-05-17 16:22:44 +03:00
return ts
2015-11-21 04:59:49 +03:00
}
2017-11-09 14:16:03 +03:00
// TestWithSNIConfigRoute involves a client sending HTTPS requests with
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
// that traefik routes the requests to the expected backends thanks to given certificate if possible
// otherwise thanks to the default one.
func ( s * HTTPSSuite ) TestWithSNIDynamicConfigRouteWithNoChange ( c * check . C ) {
dynamicConfFileName := s . adaptFile ( c , "fixtures/https/dynamic_https.toml" , struct { } { } )
defer os . Remove ( dynamicConfFileName )
confFileName := s . adaptFile ( c , "fixtures/https/dynamic_https_sni.toml" , struct {
DynamicConfFileName string
} {
DynamicConfFileName : dynamicConfFileName ,
} )
defer os . Remove ( confFileName )
cmd , display := s . traefikCmd ( withConfigFile ( confFileName ) )
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
tr1 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.org" ,
} ,
}
tr2 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
} ,
}
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 1 * time . Second , try . BodyContains ( "Host:" + tr1 . TLSClientConfig . ServerName ) )
c . Assert ( err , checker . IsNil )
backend1 := startTestServer ( "9010" , http . StatusNoContent )
backend2 := startTestServer ( "9020" , http . StatusResetContent )
defer backend1 . Close ( )
defer backend2 . Close ( )
err = try . GetRequest ( backend1 . URL , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusNoContent ) )
c . Assert ( err , checker . IsNil )
err = try . GetRequest ( backend2 . URL , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusResetContent ) )
c . Assert ( err , checker . IsNil )
client := & http . Client { Transport : tr1 }
req , err := http . NewRequest ( http . MethodGet , "https://127.0.0.1:4443/" , nil )
c . Assert ( err , checker . IsNil )
req . Host = tr1 . TLSClientConfig . ServerName
req . Header . Set ( "Host" , tr1 . TLSClientConfig . ServerName )
req . Header . Set ( "Accept" , "*/*" )
resp , err := client . Do ( req )
c . Assert ( err , checker . IsNil )
// snitest.org certificate must be used yet
c . Assert ( resp . TLS . PeerCertificates [ 0 ] . Subject . CommonName , check . Equals , tr1 . TLSClientConfig . ServerName )
// Expected a 204 (from backend1)
c . Assert ( resp . StatusCode , checker . Equals , http . StatusResetContent )
client = & http . Client { Transport : tr2 }
req . Host = tr2 . TLSClientConfig . ServerName
req . Header . Set ( "Host" , tr2 . TLSClientConfig . ServerName )
resp , err = client . Do ( req )
c . Assert ( err , checker . IsNil )
// snitest.com certificate does not exist, default certificate has to be used
c . Assert ( resp . TLS . PeerCertificates [ 0 ] . Subject . CommonName , checker . Not ( check . Equals ) , tr2 . TLSClientConfig . ServerName )
// Expected a 205 (from backend2)
c . Assert ( resp . StatusCode , checker . Equals , http . StatusNoContent )
}
// TestWithSNIConfigRoute involves a client sending HTTPS requests with
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
// that traefik updates its configuration when the HTTPS configuration is modified and
// it routes the requests to the expected backends thanks to given certificate if possible
// otherwise thanks to the default one.
func ( s * HTTPSSuite ) TestWithSNIDynamicConfigRouteWithChange ( c * check . C ) {
dynamicConfFileName := s . adaptFile ( c , "fixtures/https/dynamic_https.toml" , struct { } { } )
defer os . Remove ( dynamicConfFileName )
confFileName := s . adaptFile ( c , "fixtures/https/dynamic_https_sni.toml" , struct {
DynamicConfFileName string
} {
DynamicConfFileName : dynamicConfFileName ,
} )
defer os . Remove ( confFileName )
cmd , display := s . traefikCmd ( withConfigFile ( confFileName ) )
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
defer cmd . Process . Kill ( )
tr1 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.com" ,
} ,
}
tr2 := & http . Transport {
TLSClientConfig : & tls . Config {
InsecureSkipVerify : true ,
ServerName : "snitest.org" ,
} ,
}
// wait for Traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/providers" , 1 * time . Second , try . BodyContains ( "Host:" + tr2 . TLSClientConfig . ServerName ) )
c . Assert ( err , checker . IsNil )
backend1 := startTestServer ( "9010" , http . StatusNoContent )
backend2 := startTestServer ( "9020" , http . StatusResetContent )
defer backend1 . Close ( )
defer backend2 . Close ( )
err = try . GetRequest ( backend1 . URL , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusNoContent ) )
c . Assert ( err , checker . IsNil )
err = try . GetRequest ( backend2 . URL , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusResetContent ) )
c . Assert ( err , checker . IsNil )
req , err := http . NewRequest ( http . MethodGet , "https://127.0.0.1:4443/" , nil )
client := & http . Client { Transport : tr1 }
req . Host = tr1 . TLSClientConfig . ServerName
req . Header . Set ( "Host" , tr1 . TLSClientConfig . ServerName )
req . Header . Set ( "Accept" , "*/*" )
// Change certificates configuration file content
modifyCertificateConfFileContent ( c , tr1 . TLSClientConfig . ServerName , dynamicConfFileName )
var resp * http . Response
err = try . Do ( 30 * time . Second , func ( ) error {
resp , err = client . Do ( req )
// /!\ If connection is not closed, SSLHandshake will only be done during the first trial /!\
req . Close = true
if err != nil {
return err
}
cn := resp . TLS . PeerCertificates [ 0 ] . Subject . CommonName
if cn != tr1 . TLSClientConfig . ServerName {
return fmt . Errorf ( "domain %s found in place of %s" , cn , tr1 . TLSClientConfig . ServerName )
}
return nil
} )
c . Assert ( err , checker . IsNil )
c . Assert ( resp . StatusCode , checker . Equals , http . StatusNotFound )
client = & http . Client { Transport : tr2 }
req . Host = tr2 . TLSClientConfig . ServerName
req . Header . Set ( "Host" , tr2 . TLSClientConfig . ServerName )
err = try . Do ( 60 * time . Second , func ( ) error {
resp , err = client . Do ( req )
// /!\ If connection is not closed, SSLHandshake will only be done during the first trial /!\
req . Close = true
if err != nil {
return err
}
cn := resp . TLS . PeerCertificates [ 0 ] . Subject . CommonName
if cn == tr2 . TLSClientConfig . ServerName {
return fmt . Errorf ( "domain %s found in place of default one" , tr2 . TLSClientConfig . ServerName )
}
return nil
} )
c . Assert ( err , checker . IsNil )
c . Assert ( resp . StatusCode , checker . Equals , http . StatusNotFound )
}
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
func modifyCertificateConfFileContent ( c * check . C , certFileName , confFileName string ) {
tlsConf := types . Configuration {
TLSConfiguration : [ ] * traefikTls . Configuration {
{
Certificate : & traefikTls . Certificate {
CertFile : traefikTls . FileOrContent ( "fixtures/https/" + certFileName + ".cert" ) ,
KeyFile : traefikTls . FileOrContent ( "fixtures/https/" + certFileName + ".key" ) ,
} ,
EntryPoints : [ ] string { "https" } ,
} ,
} ,
}
var confBuffer bytes . Buffer
e := toml . NewEncoder ( & confBuffer )
err := e . Encode ( tlsConf )
c . Assert ( err , checker . IsNil )
f , err := os . OpenFile ( "./" + confFileName , os . O_WRONLY , os . ModeExclusive )
c . Assert ( err , checker . IsNil )
defer func ( ) {
f . Close ( )
} ( )
f . Truncate ( 0 )
_ , err = f . Write ( confBuffer . Bytes ( ) )
c . Assert ( err , checker . IsNil )
}