200 lines
6.1 KiB
Go
200 lines
6.1 KiB
Go
package validation
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"testing"
|
|
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestValidateHostname(t *testing.T) {
|
|
var inputHostname string
|
|
hostname, err := ValidateHostname(inputHostname)
|
|
assert.Equal(t, err, nil)
|
|
assert.Empty(t, hostname)
|
|
|
|
inputHostname = "hello.example.com"
|
|
hostname, err = ValidateHostname(inputHostname)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "hello.example.com", hostname)
|
|
|
|
inputHostname = "http://hello.example.com"
|
|
hostname, err = ValidateHostname(inputHostname)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "hello.example.com", hostname)
|
|
|
|
inputHostname = "bücher.example.com"
|
|
hostname, err = ValidateHostname(inputHostname)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "xn--bcher-kva.example.com", hostname)
|
|
|
|
inputHostname = "http://bücher.example.com"
|
|
hostname, err = ValidateHostname(inputHostname)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "xn--bcher-kva.example.com", hostname)
|
|
|
|
inputHostname = "http%3A%2F%2Fhello.example.com"
|
|
hostname, err = ValidateHostname(inputHostname)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "hello.example.com", hostname)
|
|
|
|
}
|
|
|
|
func TestValidateUrl(t *testing.T) {
|
|
type testCase struct {
|
|
input string
|
|
expectedOutput string
|
|
}
|
|
testCases := []testCase{
|
|
{"http://localhost", "http://localhost"},
|
|
{"http://localhost/", "http://localhost"},
|
|
{"http://localhost/api", "http://localhost"},
|
|
{"http://localhost/api/", "http://localhost"},
|
|
{"https://localhost", "https://localhost"},
|
|
{"https://localhost/", "https://localhost"},
|
|
{"https://localhost/api", "https://localhost"},
|
|
{"https://localhost/api/", "https://localhost"},
|
|
{"https://localhost:8080", "https://localhost:8080"},
|
|
{"https://localhost:8080/", "https://localhost:8080"},
|
|
{"https://localhost:8080/api", "https://localhost:8080"},
|
|
{"https://localhost:8080/api/", "https://localhost:8080"},
|
|
{"localhost", "http://localhost"},
|
|
{"localhost/", "http://localhost/"},
|
|
{"localhost/api", "http://localhost/api"},
|
|
{"localhost/api/", "http://localhost/api/"},
|
|
{"localhost:8080", "http://localhost:8080"},
|
|
{"localhost:8080/", "http://localhost:8080/"},
|
|
{"localhost:8080/api", "http://localhost:8080/api"},
|
|
{"localhost:8080/api/", "http://localhost:8080/api/"},
|
|
{"localhost:8080/api/?asdf", "http://localhost:8080/api/?asdf"},
|
|
{"http://127.0.0.1:8080", "http://127.0.0.1:8080"},
|
|
{"127.0.0.1:8080", "http://127.0.0.1:8080"},
|
|
{"127.0.0.1", "http://127.0.0.1"},
|
|
{"https://127.0.0.1:8080", "https://127.0.0.1:8080"},
|
|
{"[::1]:8080", "http://[::1]:8080"},
|
|
{"http://[::1]", "http://[::1]"},
|
|
{"http://[::1]:8080", "http://[::1]:8080"},
|
|
{"[::1]", "http://[::1]"},
|
|
{"https://example.com", "https://example.com"},
|
|
{"example.com", "http://example.com"},
|
|
{"http://hello.example.com", "http://hello.example.com"},
|
|
{"hello.example.com", "http://hello.example.com"},
|
|
{"hello.example.com:8080", "http://hello.example.com:8080"},
|
|
{"https://hello.example.com:8080", "https://hello.example.com:8080"},
|
|
{"https://bücher.example.com", "https://xn--bcher-kva.example.com"},
|
|
{"bücher.example.com", "http://xn--bcher-kva.example.com"},
|
|
{"https%3A%2F%2Fhello.example.com", "https://hello.example.com"},
|
|
{"https://alex:12345@hello.example.com:8080", "https://hello.example.com:8080"},
|
|
}
|
|
for i, testCase := range testCases {
|
|
validUrl, err := ValidateUrl(testCase.input)
|
|
assert.NoError(t, err, "test case %v", i)
|
|
assert.Equal(t, testCase.expectedOutput, validUrl.String(), "test case %v", i)
|
|
}
|
|
|
|
validUrl, err := ValidateUrl("")
|
|
assert.Equal(t, fmt.Errorf("URL should not be empty"), err)
|
|
assert.Empty(t, validUrl)
|
|
|
|
validUrl, err = ValidateUrl("ftp://alex:12345@hello.example.com:8080/robot.txt")
|
|
assert.Equal(t, "Currently Cloudflare Tunnel does not support ftp protocol.", err.Error())
|
|
assert.Empty(t, validUrl)
|
|
|
|
}
|
|
|
|
func TestNewAccessValidatorOk(t *testing.T) {
|
|
ctx := context.Background()
|
|
url := "test.cloudflareaccess.com"
|
|
access, err := NewAccessValidator(ctx, url, url, "")
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, access)
|
|
|
|
assert.Error(t, access.Validate(ctx, ""))
|
|
assert.Error(t, access.Validate(ctx, "invalid"))
|
|
|
|
req := httptest.NewRequest("GET", "https://test.cloudflareaccess.com", nil)
|
|
req.Header.Set(accessJwtHeader, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")
|
|
assert.Error(t, access.ValidateRequest(ctx, req))
|
|
}
|
|
|
|
func TestNewAccessValidatorErr(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
urls := []string{
|
|
"",
|
|
"ftp://test.cloudflareaccess.com",
|
|
"wss://cloudflarenone.com",
|
|
}
|
|
|
|
for _, url := range urls {
|
|
access, err := NewAccessValidator(ctx, url, url, "")
|
|
|
|
assert.Error(t, err, url)
|
|
assert.Nil(t, access)
|
|
}
|
|
}
|
|
|
|
type testRoundTripper func(req *http.Request) (*http.Response, error)
|
|
|
|
func (f testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return f(req)
|
|
}
|
|
|
|
func emptyResponse(statusCode int) *http.Response {
|
|
return &http.Response{
|
|
StatusCode: statusCode,
|
|
Body: io.NopCloser(bytes.NewReader(nil)),
|
|
Header: make(http.Header),
|
|
}
|
|
}
|
|
|
|
func createMockServerAndClient(handler http.Handler) (*httptest.Server, *http.Client, error) {
|
|
client := http.DefaultClient
|
|
server := httptest.NewServer(handler)
|
|
|
|
client.Transport = &http.Transport{
|
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
|
return url.Parse(server.URL)
|
|
},
|
|
}
|
|
|
|
return server, client, nil
|
|
}
|
|
|
|
func createSecureMockServerAndClient(handler http.Handler) (*httptest.Server, *http.Client, error) {
|
|
client := http.DefaultClient
|
|
server := httptest.NewTLSServer(handler)
|
|
|
|
cert, err := x509.ParseCertificate(server.TLS.Certificates[0].Certificate[0])
|
|
if err != nil {
|
|
server.Close()
|
|
return nil, nil, err
|
|
}
|
|
|
|
certpool := x509.NewCertPool()
|
|
certpool.AddCert(cert)
|
|
|
|
client.Transport = &http.Transport{
|
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return net.Dial("tcp", server.URL[strings.LastIndex(server.URL, "/")+1:])
|
|
},
|
|
TLSClientConfig: &tls.Config{
|
|
RootCAs: certpool,
|
|
},
|
|
}
|
|
|
|
return server, client, nil
|
|
}
|