mirror of https://github.com/fatedier/frp
Added optional HTTPS client certificate authentication to https2http and https2https
parent
773169e0c4
commit
acb53acb2e
43
README.md
43
README.md
|
@ -89,6 +89,7 @@ frp also offers a P2P connect mode.
|
||||||
* [HTTP X-Forwarded-For](#http-x-forwarded-for)
|
* [HTTP X-Forwarded-For](#http-x-forwarded-for)
|
||||||
* [Proxy Protocol](#proxy-protocol)
|
* [Proxy Protocol](#proxy-protocol)
|
||||||
* [Require HTTP Basic Auth (Password) for Web Services](#require-http-basic-auth-password-for-web-services)
|
* [Require HTTP Basic Auth (Password) for Web Services](#require-http-basic-auth-password-for-web-services)
|
||||||
|
* [Require HTTPS client certificate for Web Services](#require-https-client-certificate-for-web-services)
|
||||||
* [Custom Subdomain Names](#custom-subdomain-names)
|
* [Custom Subdomain Names](#custom-subdomain-names)
|
||||||
* [URL Routing](#url-routing)
|
* [URL Routing](#url-routing)
|
||||||
* [TCP Port Multiplexing](#tcp-port-multiplexing)
|
* [TCP Port Multiplexing](#tcp-port-multiplexing)
|
||||||
|
@ -1046,11 +1047,11 @@ You can enable Proxy Protocol support in nginx to expose user's real IP in HTTP
|
||||||
|
|
||||||
### Require HTTP Basic Auth (Password) for Web Services
|
### Require HTTP Basic Auth (Password) for Web Services
|
||||||
|
|
||||||
Anyone who can guess your tunnel URL can access your local web server unless you protect it with a password.
|
Anyone who can guess your HTTP tunnel URL can access your local web server unless you protect it with a password.
|
||||||
|
|
||||||
This enforces HTTP Basic Auth on all requests with the username and password specified in frpc's configure file.
|
This enforces HTTP Basic Auth on all requests with the username and password specified in frpc's configure file.
|
||||||
|
|
||||||
It can only be enabled when proxy type is http.
|
It can only be enabled when proxy type is http. For https protection, see [Require HTTPS client certificate for Web Services](#require-https-client-certificate-for-web-services).
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# frpc.toml
|
# frpc.toml
|
||||||
|
@ -1066,6 +1067,44 @@ httpPassword = "abc"
|
||||||
|
|
||||||
Visit `http://test.example.com` in the browser and now you are prompted to enter the username and password.
|
Visit `http://test.example.com` in the browser and now you are prompted to enter the username and password.
|
||||||
|
|
||||||
|
### Require HTTPS client certificate for Web Services
|
||||||
|
|
||||||
|
Anyone who can guess your HTTPS tunnel URL can access your local web server unless you protect it with a [Client Certificate](https://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake).
|
||||||
|
|
||||||
|
This [mutual authentication](https://en.wikipedia.org/wiki/Mutual_authentication) validates the HTTPS client's certificate on all requests, with each accepted certificate file specified in frpc's configure file.
|
||||||
|
|
||||||
|
It can only be enabled when proxy type is https. For http protection, see [Require HTTP Basic Auth (Password) for Web Services](#require-http-basic-auth-password-for-web-services).
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[proxies]]
|
||||||
|
name = "web"
|
||||||
|
type = "https"
|
||||||
|
customDomains = ["test.example.com"]
|
||||||
|
|
||||||
|
[proxies.plugin]
|
||||||
|
type = "https2http"
|
||||||
|
localAddr = "127.0.0.1:80"
|
||||||
|
crtPath = server.crt"
|
||||||
|
keyPath = "key.pem"
|
||||||
|
clientCertificates = ["authorizedClient_cert.pem"]
|
||||||
|
```
|
||||||
|
|
||||||
|
In this situation, the client certificate can be self-signed without any detriment to security. Multiple certificates can be generated and allowed to access the service.
|
||||||
|
|
||||||
|
Generate a .cert file **to use with frpc**, and a corresponding .pfx file **to install on Windows, Linux, or your browser**. The following instructions require the OpenSSL binary installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout authorizedClient_cert.pem -out authorizedClient_key.pem -sha256 -days 3650 -nodes -subj "/CN=FRP Authentication Certificate"
|
||||||
|
type authorizedClient_cert.pem authorizedClient_key.pem > authorizedClient.pem
|
||||||
|
openssl pkcs12 -export -in authorizedClient.pem -out authorizedClient.pfx -name "FRP Authentication Certificate"
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout authorizedClient_cert.pem -out authorizedClient_key.pem -sha256 -days 3650 -nodes -subj "/CN=FRP Authentication Certificate"
|
||||||
|
cat authorizedClient_cert.pem authorizedClient_key.pem > authorizedClient.pem
|
||||||
|
openssl pkcs12 -export -in authorizedClient.pem -out authorizedClient.pfx -name "FRP Authentication Certificate"
|
||||||
|
```
|
||||||
|
|
||||||
### Custom Subdomain Names
|
### Custom Subdomain Names
|
||||||
|
|
||||||
It is convenient to use `subdomain` configure for http and https types when many people share one frps server.
|
It is convenient to use `subdomain` configure for http and https types when many people share one frps server.
|
||||||
|
|
|
@ -116,13 +116,14 @@ type HTTPProxyPluginOptions struct {
|
||||||
func (o *HTTPProxyPluginOptions) Complete() {}
|
func (o *HTTPProxyPluginOptions) Complete() {}
|
||||||
|
|
||||||
type HTTPS2HTTPPluginOptions struct {
|
type HTTPS2HTTPPluginOptions struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
LocalAddr string `json:"localAddr,omitempty"`
|
LocalAddr string `json:"localAddr,omitempty"`
|
||||||
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
|
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
|
||||||
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
|
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
|
||||||
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
|
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
|
||||||
CrtPath string `json:"crtPath,omitempty"`
|
CrtPath string `json:"crtPath,omitempty"`
|
||||||
KeyPath string `json:"keyPath,omitempty"`
|
KeyPath string `json:"keyPath,omitempty"`
|
||||||
|
ClientCertificates []string `json:"clientCertificates,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *HTTPS2HTTPPluginOptions) Complete() {
|
func (o *HTTPS2HTTPPluginOptions) Complete() {
|
||||||
|
@ -130,13 +131,14 @@ func (o *HTTPS2HTTPPluginOptions) Complete() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPS2HTTPSPluginOptions struct {
|
type HTTPS2HTTPSPluginOptions struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
LocalAddr string `json:"localAddr,omitempty"`
|
LocalAddr string `json:"localAddr,omitempty"`
|
||||||
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
|
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
|
||||||
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
|
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
|
||||||
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
|
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
|
||||||
CrtPath string `json:"crtPath,omitempty"`
|
CrtPath string `json:"crtPath,omitempty"`
|
||||||
KeyPath string `json:"keyPath,omitempty"`
|
KeyPath string `json:"keyPath,omitempty"`
|
||||||
|
ClientCertificates []string `json:"clientCertificates,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *HTTPS2HTTPSPluginOptions) Complete() {
|
func (o *HTTPS2HTTPSPluginOptions) Complete() {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package plugin
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
|
@ -91,6 +92,33 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||||
return nil, fmt.Errorf("gen TLS config error: %v", err)
|
return nil, fmt.Errorf("gen TLS config error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(p.opts.ClientCertificates) > 0 {
|
||||||
|
certs, err := transport.LoadCertificatesFromFiles(p.opts.ClientCertificates)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("loading Client Certificates failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig.ClientAuth = tls.RequireAnyClientCert
|
||||||
|
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
if len(rawCerts) == 0 {
|
||||||
|
return fmt.Errorf("no client certificate provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
clientCert, err := x509.ParseCertificate(rawCerts[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse client certificate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, allowedCert := range certs {
|
||||||
|
if clientCert.Equal(allowedCert) {
|
||||||
|
return nil //match found, accept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("client certificate not recognized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.s = &http.Server{
|
p.s = &http.Server{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
ReadHeaderTimeout: 60 * time.Second,
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
|
|
|
@ -19,6 +19,7 @@ package plugin
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
|
@ -97,6 +98,33 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||||
return nil, fmt.Errorf("gen TLS config error: %v", err)
|
return nil, fmt.Errorf("gen TLS config error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(p.opts.ClientCertificates) > 0 {
|
||||||
|
certs, err := transport.LoadCertificatesFromFiles(p.opts.ClientCertificates)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("loading Client Certificates failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig.ClientAuth = tls.RequireAnyClientCert
|
||||||
|
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
if len(rawCerts) == 0 {
|
||||||
|
return fmt.Errorf("no client certificate provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
clientCert, err := x509.ParseCertificate(rawCerts[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse client certificate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, allowedCert := range certs {
|
||||||
|
if clientCert.Equal(allowedCert) {
|
||||||
|
return nil //match found, accept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("client certificate not recognized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.s = &http.Server{
|
p.s = &http.Server{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
ReadHeaderTimeout: 60 * time.Second,
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
@ -140,3 +141,28 @@ func NewRandomPrivateKey() ([]byte, error) {
|
||||||
})
|
})
|
||||||
return keyPEM, nil
|
return keyPEM, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadCertificatesFromFiles(certFiles []string) ([]*x509.Certificate, error) {
|
||||||
|
var certificates []*x509.Certificate
|
||||||
|
|
||||||
|
for _, file := range certFiles {
|
||||||
|
certPEM, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read certificate file %s: %w", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode(certPEM)
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode PEM block")
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse certificate file %s: %w", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
certificates = append(certificates, cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificates, nil
|
||||||
|
}
|
||||||
|
|
|
@ -236,67 +236,126 @@ var _ = ginkgo.Describe("[Feature: Client-Plugins]", func() {
|
||||||
Ensure()
|
Ensure()
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.It("https2http", func() {
|
ginkgo.Describe("https2http", func() {
|
||||||
generator := &cert.SelfSignedCertGenerator{}
|
ginkgo.It("without client certificate requirement", func() {
|
||||||
artifacts, err := generator.Generate("example.com")
|
generator := &cert.SelfSignedCertGenerator{}
|
||||||
framework.ExpectNoError(err)
|
artifacts, err := generator.Generate("example.com")
|
||||||
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
framework.ExpectNoError(err)
|
||||||
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
||||||
|
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
||||||
|
|
||||||
serverConf := consts.DefaultServerConfig
|
serverConf := consts.DefaultServerConfig
|
||||||
vhostHTTPSPort := f.AllocPort()
|
vhostHTTPSPort := f.AllocPort()
|
||||||
serverConf += fmt.Sprintf(`
|
serverConf += fmt.Sprintf(`
|
||||||
vhostHTTPSPort = %d
|
vhostHTTPSPort = %d
|
||||||
`, vhostHTTPSPort)
|
`, vhostHTTPSPort)
|
||||||
|
|
||||||
localPort := f.AllocPort()
|
localPort := f.AllocPort()
|
||||||
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
||||||
[[proxies]]
|
[[proxies]]
|
||||||
name = "https2http"
|
name = "https2http"
|
||||||
type = "https"
|
type = "https"
|
||||||
customDomains = ["example.com"]
|
customDomains = ["example.com"]
|
||||||
[proxies.plugin]
|
[proxies.plugin]
|
||||||
type = "https2http"
|
type = "https2http"
|
||||||
localAddr = "127.0.0.1:%d"
|
localAddr = "127.0.0.1:%d"
|
||||||
crtPath = "%s"
|
crtPath = "%s"
|
||||||
keyPath = "%s"
|
keyPath = "%s"
|
||||||
`, localPort, crtPath, keyPath)
|
`, localPort, crtPath, keyPath)
|
||||||
|
|
||||||
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||||
|
|
||||||
localServer := httpserver.New(
|
localServer := httpserver.New(
|
||||||
httpserver.WithBindPort(localPort),
|
httpserver.WithBindPort(localPort),
|
||||||
httpserver.WithResponse([]byte("test")),
|
httpserver.WithResponse([]byte("test")),
|
||||||
)
|
)
|
||||||
f.RunServer("", localServer)
|
f.RunServer("", localServer)
|
||||||
|
|
||||||
framework.NewRequestExpect(f).
|
framework.NewRequestExpect(f).
|
||||||
Port(vhostHTTPSPort).
|
Port(vhostHTTPSPort).
|
||||||
RequestModify(func(r *request.Request) {
|
RequestModify(func(r *request.Request) {
|
||||||
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
||||||
ServerName: "example.com",
|
ServerName: "example.com",
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
})
|
})
|
||||||
}).
|
}).
|
||||||
ExpectResp([]byte("test")).
|
ExpectResp([]byte("test")).
|
||||||
Ensure()
|
Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("with client certificate requirement", func() {
|
||||||
|
generator := &cert.SelfSignedCertGenerator{}
|
||||||
|
artifacts, err := generator.Generate("example.com")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
||||||
|
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
||||||
|
|
||||||
|
artifacts, err = generator.Generate("127.0.0.1")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
clientCrtPath := f.WriteTempFile("client.crt", string(artifacts.Cert))
|
||||||
|
clientKeyPath := f.WriteTempFile("client.key", string(artifacts.Key))
|
||||||
|
|
||||||
|
serverConf := consts.DefaultServerConfig
|
||||||
|
vhostHTTPSPort := f.AllocPort()
|
||||||
|
serverConf += fmt.Sprintf(`
|
||||||
|
vhostHTTPSPort = %d
|
||||||
|
`, vhostHTTPSPort)
|
||||||
|
|
||||||
|
localPort := f.AllocPort()
|
||||||
|
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
||||||
|
[[proxies]]
|
||||||
|
name = "https2http"
|
||||||
|
type = "https"
|
||||||
|
customDomains = ["example.com"]
|
||||||
|
[proxies.plugin]
|
||||||
|
type = "https2http"
|
||||||
|
localAddr = "127.0.0.1:%d"
|
||||||
|
crtPath = "%s"
|
||||||
|
keyPath = "%s"
|
||||||
|
clientCertificates = ["%s"]
|
||||||
|
`, localPort, crtPath, keyPath, clientCrtPath)
|
||||||
|
|
||||||
|
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||||
|
|
||||||
|
localServer := httpserver.New(
|
||||||
|
httpserver.WithBindPort(localPort),
|
||||||
|
httpserver.WithResponse([]byte("test")),
|
||||||
|
)
|
||||||
|
f.RunServer("", localServer)
|
||||||
|
|
||||||
|
clientCertificate, err := tls.LoadX509KeyPair(clientCrtPath, clientKeyPath)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).
|
||||||
|
Port(vhostHTTPSPort).
|
||||||
|
RequestModify(func(r *request.Request) {
|
||||||
|
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
||||||
|
ServerName: "example.com",
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
Certificates: []tls.Certificate{clientCertificate},
|
||||||
|
})
|
||||||
|
}).
|
||||||
|
ExpectResp([]byte("test")).
|
||||||
|
Ensure()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.It("https2https", func() {
|
ginkgo.Describe("https2https", func() {
|
||||||
generator := &cert.SelfSignedCertGenerator{}
|
ginkgo.It("without client certificate requirement", func() {
|
||||||
artifacts, err := generator.Generate("example.com")
|
generator := &cert.SelfSignedCertGenerator{}
|
||||||
framework.ExpectNoError(err)
|
artifacts, err := generator.Generate("example.com")
|
||||||
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
framework.ExpectNoError(err)
|
||||||
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
||||||
|
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
||||||
|
|
||||||
serverConf := consts.DefaultServerConfig
|
serverConf := consts.DefaultServerConfig
|
||||||
vhostHTTPSPort := f.AllocPort()
|
vhostHTTPSPort := f.AllocPort()
|
||||||
serverConf += fmt.Sprintf(`
|
serverConf += fmt.Sprintf(`
|
||||||
vhostHTTPSPort = %d
|
vhostHTTPSPort = %d
|
||||||
`, vhostHTTPSPort)
|
`, vhostHTTPSPort)
|
||||||
|
|
||||||
localPort := f.AllocPort()
|
localPort := f.AllocPort()
|
||||||
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
||||||
[[proxies]]
|
[[proxies]]
|
||||||
name = "https2https"
|
name = "https2https"
|
||||||
type = "https"
|
type = "https"
|
||||||
|
@ -308,27 +367,87 @@ var _ = ginkgo.Describe("[Feature: Client-Plugins]", func() {
|
||||||
keyPath = "%s"
|
keyPath = "%s"
|
||||||
`, localPort, crtPath, keyPath)
|
`, localPort, crtPath, keyPath)
|
||||||
|
|
||||||
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||||
|
|
||||||
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
|
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
|
||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
localServer := httpserver.New(
|
localServer := httpserver.New(
|
||||||
httpserver.WithBindPort(localPort),
|
httpserver.WithBindPort(localPort),
|
||||||
httpserver.WithResponse([]byte("test")),
|
httpserver.WithResponse([]byte("test")),
|
||||||
httpserver.WithTLSConfig(tlsConfig),
|
httpserver.WithTLSConfig(tlsConfig),
|
||||||
)
|
)
|
||||||
f.RunServer("", localServer)
|
f.RunServer("", localServer)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).
|
||||||
|
Port(vhostHTTPSPort).
|
||||||
|
RequestModify(func(r *request.Request) {
|
||||||
|
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
||||||
|
ServerName: "example.com",
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
})
|
||||||
|
}).
|
||||||
|
ExpectResp([]byte("test")).
|
||||||
|
Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("with client certificate requirement", func() {
|
||||||
|
generator := &cert.SelfSignedCertGenerator{}
|
||||||
|
artifacts, err := generator.Generate("example.com")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
|
||||||
|
keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
|
||||||
|
artifacts, err = generator.Generate("127.0.0.1")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
clientCrtPath := f.WriteTempFile("client.crt", string(artifacts.Cert))
|
||||||
|
clientKeyPath := f.WriteTempFile("client.key", string(artifacts.Key))
|
||||||
|
|
||||||
|
serverConf := consts.DefaultServerConfig
|
||||||
|
vhostHTTPSPort := f.AllocPort()
|
||||||
|
serverConf += fmt.Sprintf(`
|
||||||
|
vhostHTTPSPort = %d
|
||||||
|
`, vhostHTTPSPort)
|
||||||
|
|
||||||
|
localPort := f.AllocPort()
|
||||||
|
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
|
||||||
|
[[proxies]]
|
||||||
|
name = "https2https"
|
||||||
|
type = "https"
|
||||||
|
customDomains = ["example.com"]
|
||||||
|
[proxies.plugin]
|
||||||
|
type = "https2https"
|
||||||
|
localAddr = "127.0.0.1:%d"
|
||||||
|
crtPath = "%s"
|
||||||
|
keyPath = "%s"
|
||||||
|
clientCertificates = ["%s"]
|
||||||
|
`, localPort, crtPath, keyPath, clientCrtPath)
|
||||||
|
|
||||||
|
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||||
|
|
||||||
|
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
localServer := httpserver.New(
|
||||||
|
httpserver.WithBindPort(localPort),
|
||||||
|
httpserver.WithResponse([]byte("test")),
|
||||||
|
httpserver.WithTLSConfig(tlsConfig),
|
||||||
|
)
|
||||||
|
f.RunServer("", localServer)
|
||||||
|
|
||||||
|
clientCertificate, err := tls.LoadX509KeyPair(clientCrtPath, clientKeyPath)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).
|
||||||
|
Port(vhostHTTPSPort).
|
||||||
|
RequestModify(func(r *request.Request) {
|
||||||
|
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
||||||
|
ServerName: "example.com",
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
Certificates: []tls.Certificate{clientCertificate},
|
||||||
|
})
|
||||||
|
}).
|
||||||
|
ExpectResp([]byte("test")).
|
||||||
|
Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
framework.NewRequestExpect(f).
|
|
||||||
Port(vhostHTTPSPort).
|
|
||||||
RequestModify(func(r *request.Request) {
|
|
||||||
r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
|
|
||||||
ServerName: "example.com",
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
})
|
|
||||||
}).
|
|
||||||
ExpectResp([]byte("test")).
|
|
||||||
Ensure()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.Describe("http2http", func() {
|
ginkgo.Describe("http2http", func() {
|
||||||
|
|
Loading…
Reference in New Issue