diff options
-rw-r--r-- | .github/workflows/ci.yml | 26 | ||||
-rw-r--r-- | modules/caddyhttp/app.go | 6 | ||||
-rw-r--r-- | modules/caddyhttp/caddyauth/caddyfile.go | 2 | ||||
-rw-r--r-- | modules/caddyhttp/replacer.go | 64 | ||||
-rw-r--r-- | modules/caddyhttp/replacer_test.go | 20 | ||||
-rw-r--r-- | modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go | 4 |
6 files changed, 117 insertions, 5 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c096fbd..e7506fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,6 +120,32 @@ jobs: # echo "step_test ${{ steps.step_test.outputs.status }}\n" # exit 1 + s390x-test: + name: test (s390x on IBM Z) + runs-on: ubuntu-latest + steps: + - name: Checkout code into the Go module directory + uses: actions/checkout@v2 + - name: Run Tests + run: | + mkdir -p ~/.ssh && echo -e "${SSH_KEY//_/\\n}" > ~/.ssh/id_ecdsa && chmod og-rwx ~/.ssh/id_ecdsa + + # short sha is enough? + short_sha=$(git rev-parse --short HEAD) + + # The environment is fresh, so there's no point in keeping accepting and adding the key. + rsync -arz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --progress --delete --exclude '.git' . caddy-ci@ci-s390x.caddyserver.com:/var/tmp/"$short_sha" + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t caddy-ci@ci-s390x.caddyserver.com "cd /var/tmp/$short_sha; CGO_ENABLED=0 /usr/local/go/bin/go test -v ./..." + test_result=$? + + # There's no need leaving the files around + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null caddy-ci@ci-s390x.caddyserver.com "rm -rf /var/tmp/'$short_sha'" + + echo "Test exit code: $test_result" + exit $test_result + env: + SSH_KEY: ${{ secrets.S390X_SSH_KEY }} + # From https://github.com/reviewdog/action-golangci-lint golangci-lint: name: runner / golangci-lint diff --git a/modules/caddyhttp/app.go b/modules/caddyhttp/app.go index f695276..45845ea 100644 --- a/modules/caddyhttp/app.go +++ b/modules/caddyhttp/app.go @@ -72,9 +72,15 @@ func init() { // `{http.request.tls.proto_mutual}` | The negotiated next protocol was advertised by the server // `{http.request.tls.server_name}` | The server name requested by the client, if any // `{http.request.tls.client.fingerprint}` | The SHA256 checksum of the client certificate +// `{http.request.tls.client.public_key}` | The public key of the client certificate. +// `{http.request.tls.client.public_key_sha256}` | The SHA256 checksum of the client's public key. // `{http.request.tls.client.issuer}` | The issuer DN of the client certificate // `{http.request.tls.client.serial}` | The serial number of the client certificate // `{http.request.tls.client.subject}` | The subject DN of the client certificate +// `{http.request.tls.client.san.dns_names.*}` | SAN DNS names(index optional) +// `{http.request.tls.client.san.emails.*}` | SAN email addresses (index optional) +// `{http.request.tls.client.san.ips.*}` | SAN IP addresses (index optional) +// `{http.request.tls.client.san.uris.*}` | SAN URIs (index optional) // `{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left) // `{http.request.uri.path.dir}` | The directory, excluding leaf filename // `{http.request.uri.path.file}` | The filename of the path, excluding directory diff --git a/modules/caddyhttp/caddyauth/caddyfile.go b/modules/caddyhttp/caddyauth/caddyfile.go index 13e78fc..afa3808 100644 --- a/modules/caddyhttp/caddyauth/caddyfile.go +++ b/modules/caddyhttp/caddyauth/caddyfile.go @@ -27,7 +27,7 @@ func init() { // parseCaddyfile sets up the handler from Caddyfile tokens. Syntax: // -// basicauth [<matcher>] [<hash_algorithm>] { +// basicauth [<matcher>] [<hash_algorithm> [<realm>]] { // <username> <hashed_password_base64> [<salt_base64>] // ... // } diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index 37b53d2..b3c7b5d 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -28,6 +28,7 @@ import ( "net" "net/http" "net/textproto" + "net/url" "path" "strconv" "strings" @@ -163,7 +164,7 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo if strings.HasPrefix(key, reqHostLabelsReplPrefix) { idxStr := key[len(reqHostLabelsReplPrefix):] idx, err := strconv.Atoi(idxStr) - if err != nil { + if err != nil || idx < 0 { return "", false } reqHost, _, err := net.SplitHostPort(req.Host) @@ -171,9 +172,6 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo reqHost = req.Host // OK; assume there was no port } hostLabels := strings.Split(reqHost, ".") - if idx < 0 { - return "", false - } if idx > len(hostLabels) { return "", true } @@ -245,6 +243,64 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) { return nil, false } + // subject alternate names (SANs) + if strings.HasPrefix(field, "client.san.") { + field = field[len("client.san."):] + var fieldName string + var fieldValue interface{} + switch { + case strings.HasPrefix(field, "dns_names"): + fieldName = "dns_names" + fieldValue = cert.DNSNames + case strings.HasPrefix(field, "emails"): + fieldName = "emails" + fieldValue = cert.EmailAddresses + case strings.HasPrefix(field, "ips"): + fieldName = "ips" + fieldValue = cert.IPAddresses + case strings.HasPrefix(field, "uris"): + fieldName = "uris" + fieldValue = cert.URIs + default: + return nil, false + } + field = field[len(fieldName):] + + // if no index was specified, return the whole list + if field == "" { + return fieldValue, true + } + if len(field) < 2 || field[0] != '.' { + return nil, false + } + field = field[1:] // trim '.' between field name and index + + // get the numeric index + idx, err := strconv.Atoi(field) + if err != nil || idx < 0 { + return nil, false + } + + // access the indexed element and return it + switch v := fieldValue.(type) { + case []string: + if idx >= len(v) { + return nil, true + } + return v[idx], true + case []net.IP: + if idx >= len(v) { + return nil, true + } + return v[idx], true + case []*url.URL: + if idx >= len(v) { + return nil, true + } + return v[idx], true + } + } + switch field { case "client.fingerprint": return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true diff --git a/modules/caddyhttp/replacer_test.go b/modules/caddyhttp/replacer_test.go index ea9fa65..bc18c5a 100644 --- a/modules/caddyhttp/replacer_test.go +++ b/modules/caddyhttp/replacer_test.go @@ -147,6 +147,26 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV input: "{http.request.tls.client.subject}", expect: "CN=client.localdomain", }, + { + input: "{http.request.tls.client.san.dns_names}", + expect: "[localhost]", + }, + { + input: "{http.request.tls.client.san.dns_names.0}", + expect: "localhost", + }, + { + input: "{http.request.tls.client.san.dns_names.1}", + expect: "<empty>", + }, + { + input: "{http.request.tls.client.san.ips}", + expect: "[127.0.0.1]", + }, + { + input: "{http.request.tls.client.san.ips.0}", + expect: "127.0.0.1", + }, } { actual := repl.ReplaceAll(tc.input, "<empty>") if actual != tc.expect { diff --git a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go index 6ad5047..4a8c6d7 100644 --- a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go +++ b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go @@ -303,6 +303,10 @@ func (t Transport) splitPos(path string) int { // if httpserver.CaseSensitivePath { // return strings.Index(path, r.SplitPath) // } + if len(t.SplitPath) == 0 { + return 0 + } + lowerPath := strings.ToLower(path) for _, split := range t.SplitPath { if idx := strings.Index(lowerPath, strings.ToLower(split)); idx > -1 { |