summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/replacer.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-03-06 23:15:25 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2020-03-06 23:15:25 -0700
commitb8cba62643abf849411856bd92c42b59b98779f4 (patch)
tree518ddc4db0ce065353fd6f499c8eaf2975b65d13 /modules/caddyhttp/replacer.go
parent7cca291d62c910c0544f0c0169a8f0c81627e5d3 (diff)
Refactor for CertMagic v0.10; prepare for PKI app
This is a breaking change primarily in two areas: - Storage paths for certificates have changed - Slight changes to JSON config parameters Huge improvements in this commit, to be detailed more in the release notes. The upcoming PKI app will be powered by Smallstep libraries.
Diffstat (limited to 'modules/caddyhttp/replacer.go')
-rw-r--r--modules/caddyhttp/replacer.go104
1 files changed, 89 insertions, 15 deletions
diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go
index cea820d..c9c7522 100644
--- a/modules/caddyhttp/replacer.go
+++ b/modules/caddyhttp/replacer.go
@@ -15,6 +15,9 @@
package caddyhttp
import (
+ "crypto/sha256"
+ "crypto/tls"
+ "crypto/x509"
"fmt"
"net"
"net/http"
@@ -24,14 +27,15 @@ import (
"strings"
"github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/modules/caddytls"
)
func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.ResponseWriter) {
httpVars := func(key string) (string, bool) {
if req != nil {
// query string parameters
- if strings.HasPrefix(key, queryReplPrefix) {
- vals := req.URL.Query()[key[len(queryReplPrefix):]]
+ if strings.HasPrefix(key, reqURIQueryReplPrefix) {
+ vals := req.URL.Query()[key[len(reqURIQueryReplPrefix):]]
// always return true, since the query param might
// be present only in some requests
return strings.Join(vals, ","), true
@@ -47,8 +51,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
}
// cookies
- if strings.HasPrefix(key, cookieReplPrefix) {
- name := key[len(cookieReplPrefix):]
+ if strings.HasPrefix(key, reqCookieReplPrefix) {
+ name := key[len(reqCookieReplPrefix):]
for _, cookie := range req.Cookies() {
if strings.EqualFold(name, cookie.Name) {
// always return true, since the cookie might
@@ -58,6 +62,11 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
}
}
+ // http.request.tls.
+ if strings.HasPrefix(key, reqTLSReplPrefix) {
+ return getReqTLSReplacement(req, key)
+ }
+
switch key {
case "http.request.method":
return req.Method, true
@@ -129,8 +138,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
}
// hostname labels
- if strings.HasPrefix(key, hostLabelReplPrefix) {
- idxStr := key[len(hostLabelReplPrefix):]
+ if strings.HasPrefix(key, reqHostLabelsReplPrefix) {
+ idxStr := key[len(reqHostLabelsReplPrefix):]
idx, err := strconv.Atoi(idxStr)
if err != nil {
return "", false
@@ -150,8 +159,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
}
// path parts
- if strings.HasPrefix(key, pathPartsReplPrefix) {
- idxStr := key[len(pathPartsReplPrefix):]
+ if strings.HasPrefix(key, reqURIPathReplPrefix) {
+ idxStr := key[len(reqURIPathReplPrefix):]
idx, err := strconv.Atoi(idxStr)
if err != nil {
return "", false
@@ -208,12 +217,77 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
repl.Map(httpVars)
}
+func getReqTLSReplacement(req *http.Request, key string) (string, bool) {
+ if req == nil || req.TLS == nil {
+ return "", false
+ }
+
+ if len(key) < len(reqTLSReplPrefix) {
+ return "", false
+ }
+
+ field := strings.ToLower(key[len(reqTLSReplPrefix):])
+
+ if strings.HasPrefix(field, "client.") {
+ cert := getTLSPeerCert(req.TLS)
+ if cert == nil {
+ return "", false
+ }
+
+ switch field {
+ case "client.fingerprint":
+ return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
+ case "client.issuer":
+ return cert.Issuer.String(), true
+ case "client.serial":
+ return fmt.Sprintf("%x", cert.SerialNumber), true
+ case "client.subject":
+ return cert.Subject.String(), true
+ default:
+ return "", false
+ }
+ }
+
+ switch field {
+ case "version":
+ return caddytls.ProtocolName(req.TLS.Version), true
+ case "cipher_suite":
+ return tls.CipherSuiteName(req.TLS.CipherSuite), true
+ case "resumed":
+ if req.TLS.DidResume {
+ return "true", true
+ }
+ return "false", true
+ case "proto":
+ return req.TLS.NegotiatedProtocol, true
+ case "proto_mutual":
+ if req.TLS.NegotiatedProtocolIsMutual {
+ return "true", true
+ }
+ return "false", true
+ case "server_name":
+ return req.TLS.ServerName, true
+ default:
+ return "", false
+ }
+}
+
+// getTLSPeerCert retrieves the first peer certificate from a TLS session.
+// Returns nil if no peer cert is in use.
+func getTLSPeerCert(cs *tls.ConnectionState) *x509.Certificate {
+ if len(cs.PeerCertificates) == 0 {
+ return nil
+ }
+ return cs.PeerCertificates[0]
+}
+
const (
- queryReplPrefix = "http.request.uri.query."
- reqHeaderReplPrefix = "http.request.header."
- cookieReplPrefix = "http.request.cookie."
- hostLabelReplPrefix = "http.request.host.labels."
- pathPartsReplPrefix = "http.request.uri.path."
- varsReplPrefix = "http.vars."
- respHeaderReplPrefix = "http.response.header."
+ reqCookieReplPrefix = "http.request.cookie."
+ reqHeaderReplPrefix = "http.request.header."
+ reqHostLabelsReplPrefix = "http.request.host.labels."
+ reqTLSReplPrefix = "http.request.tls."
+ reqURIPathReplPrefix = "http.request.uri.path."
+ reqURIQueryReplPrefix = "http.request.uri.query."
+ respHeaderReplPrefix = "http.response.header."
+ varsReplPrefix = "http.vars."
)