diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 86b1ede2652..394b6d62a7d 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -757,6 +757,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - Update Cisco ASA/FTD ingest pipeline grok/dissect patterns for multiple message IDs. {issue}26869[26869] {pull}26879[26879] - Add write access to `url.value` from `request.transforms` in `httpjson` input. {pull}27937[27937] - Add Akamai EdgeGrid authenication to `httpjson` input {pull}27873[27873] +- Add Base64 encoded HMAC and UUID template functions to `httpjson` input {pull}27873[27873] *Heartbeat* diff --git a/go.mod b/go.mod index 07baf547449..25c03329e8f 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,7 @@ require ( github.com/google/flatbuffers v1.12.0 github.com/google/go-cmp v0.5.4 github.com/google/gopacket v1.1.18-0.20191009163724-0ad7f2610e34 - github.com/google/uuid v1.1.2 + github.com/google/uuid v1.3.0 github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/gorilla/mux v1.7.2 github.com/grpc-ecosystem/grpc-gateway v1.13.0 // indirect diff --git a/go.sum b/go.sum index 79373668286..68cfd3c523e 100644 --- a/go.sum +++ b/go.sum @@ -405,6 +405,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= diff --git a/x-pack/filebeat/docs/inputs/input-httpjson.asciidoc b/x-pack/filebeat/docs/inputs/input-httpjson.asciidoc index 0585f10d46e..4180cab1b07 100644 --- a/x-pack/filebeat/docs/inputs/input-httpjson.asciidoc +++ b/x-pack/filebeat/docs/inputs/input-httpjson.asciidoc @@ -202,11 +202,13 @@ Some built-in helper functions are provided to work with the input state inside - `add`: adds a list of integers and returns their sum. - `mul`: multiplies two integers. - `div`: does the integer division of two integer values. -- `hmac`: calculates the hmac signature of a list of strings concatenated together. Supports sha1 or sha256. Example `[[hmac "sha256" "secret" "string1" "string2" (formatDate (now) "RFC1123")]]` +- `hmac`: calculates the hmac signature of a list of strings concatenated together. Returns a hex encoded signature. Supports sha1 or sha256. Example `[[hmac "sha256" "secret" "string1" "string2" (formatDate (now) "RFC1123")]]` - `base64Encode`: Joins and base64 encodes all supplied strings. Example `[[base64Encode "string1" "string2"]]` - `base64EncodeNoPad`: Joins and base64 encodes all supplied strings without padding. Example `[[base64EncodeNoPad "string1" "string2"]]` - `join`: joins a list of strings using the specified separator. Example: `[[join .body.arr ","]]` - `sprintf`: formats according to a format specifier and returns the resulting string. Refer to https://pkg.go.dev/fmt#Sprintf[the Go docs] for usage. Example: `[[sprintf "%d:%q" 34 "quote this"]]` +- `hmacBase64`: calculates the hmac signature of a list of strings concatenated together. Returns a base64 encoded signature. Supports sha1 or sha256. Example `[[hmac "sha256" "secret" "string1" "string2" (formatDate (now) "RFC1123")]]` +- `uuid`: returns a random UUID such as `a11e8780-e3e7-46d0-8e76-f66e75acf019` Example: `[[ uuid ]]` In addition to the provided functions, any of the native functions for https://golang.org/pkg/time/#Time[`time.Time`], https://golang.org/pkg/net/http/#Header[`http.Header`], and https://golang.org/pkg/net/url/#Values[`url.Values`] types can be used on the corresponding objects. Examples: `[[(now).Day]]`, `[[.last_response.header.Get "key"]]` diff --git a/x-pack/filebeat/input/httpjson/internal/v2/value_tpl.go b/x-pack/filebeat/input/httpjson/internal/v2/value_tpl.go index ed00cf97bbe..7d779f04844 100644 --- a/x-pack/filebeat/input/httpjson/internal/v2/value_tpl.go +++ b/x-pack/filebeat/input/httpjson/internal/v2/value_tpl.go @@ -22,6 +22,7 @@ import ( "time" "github.com/elastic/beats/v7/libbeat/logp" + "github.com/google/uuid" ) // we define custom delimiters to prevent issues when using template values as part of other Go templates. @@ -56,11 +57,12 @@ func (t *valueTpl) Unpack(in string) error { "mul": mul, "div": div, "hmac": hmacStringHex, - "hmacBase64": hmacStringBase64, "base64Encode": base64Encode, "base64EncodeNoPad": base64EncodeNoPad, "join": strings.Join, "sprintf": fmt.Sprintf, + "hmacBase64": hmacStringBase64, + "uuid": uuidString, }). Delims(leftDelim, rightDelim). Parse(in) @@ -310,3 +312,11 @@ func hmacStringBase64(hmacType string, hmacKey string, values ...string) string // Get result and encode as hexadecimal string return base64.StdEncoding.EncodeToString(bytes) } + +func uuidString() string { + uuid, err := uuid.NewRandom() + if err != nil { + return "" + } + return uuid.String() +} diff --git a/x-pack/filebeat/input/httpjson/internal/v2/value_tpl_test.go b/x-pack/filebeat/input/httpjson/internal/v2/value_tpl_test.go index 4586dec7711..cd9f37bd48b 100644 --- a/x-pack/filebeat/input/httpjson/internal/v2/value_tpl_test.go +++ b/x-pack/filebeat/input/httpjson/internal/v2/value_tpl_test.go @@ -253,14 +253,14 @@ func TestValueTpl(t *testing.T) { expectedVal: "4", }, { - name: "func sha1 hmac", + name: "func sha1 hmac Hex", value: `[[hmac "sha1" "secret" "string1" "string2"]]`, paramCtx: emptyTransformContext(), paramTr: transformable{}, expectedVal: "87eca1e7cba012b2dd4a907c2ad4345a252a38f4", }, { - name: "func sha256 hmac", + name: "func sha256 hmac Hex", setup: func() { timeNow = func() time.Time { return time.Unix(1627697597, 0).UTC() } }, teardown: func() { timeNow = time.Now }, value: `[[hmac "sha256" "secret" "string1" "string2" (formatDate (now) "RFC1123")]]`, @@ -269,7 +269,7 @@ func TestValueTpl(t *testing.T) { expectedVal: "adc61cd206e146f2d1337504e760ea70f3d2e34bedf28d07802e0e776568a06b", }, { - name: "func invalid hmac", + name: "func invalid hmac Hex", value: `[[hmac "md5" "secret" "string1" "string2"]]`, paramCtx: emptyTransformContext(), paramTr: transformable{}, @@ -331,6 +331,30 @@ func TestValueTpl(t *testing.T) { paramTr: transformable{}, expectedVal: `"foo,bar":1`, }, + { + name: "func sha1 hmac Base64", + value: `[[hmacBase64 "sha1" "secret" "string1" "string2"]]`, + paramCtx: emptyTransformContext(), + paramTr: transformable{}, + expectedVal: "h+yh58ugErLdSpB8KtQ0WiUqOPQ=", + }, + { + name: "func sha256 hmac Base64", + setup: func() { timeNow = func() time.Time { return time.Unix(1627697597, 0).UTC() } }, + teardown: func() { timeNow = time.Now }, + value: `[[hmacBase64 "sha256" "secret" "string1" "string2"]]`, + paramCtx: emptyTransformContext(), + paramTr: transformable{}, + expectedVal: "HlglO6yRZs0Ts3MjmgnRKtTJk3fr9nt8LmeliVKZyAA=", + }, + { + name: "func invalid hmac Base64", + value: `[[hmacBase64 "md5" "secret" "string1" "string2"]]`, + paramCtx: emptyTransformContext(), + paramTr: transformable{}, + expectedVal: "", + expectedError: errEmptyTemplateResult.Error(), + }, } for _, tc := range cases {