summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml26
-rw-r--r--modules/caddyhttp/app.go6
-rw-r--r--modules/caddyhttp/caddyauth/caddyfile.go2
-rw-r--r--modules/caddyhttp/replacer.go64
-rw-r--r--modules/caddyhttp/replacer_test.go20
-rw-r--r--modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go4
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 {