Browse Source

Only URL encode data being passed to URLs (#3652) (#3674)

Signed-off-by: Ryan Means <ryan.means@pangea.cloud>
Co-authored-by: Ryan Means <ryan.means@pangea.cloud>
RMeans 1 year ago
parent
commit
43ee65f957

+ 23 - 9
pkg/common/webhook/webhook.go

@@ -116,13 +116,21 @@ func (w *Webhook) GetSecretMap(ctx context.Context, provider *Spec, ref *esv1bet
 	return values, nil
 }
 
-func (w *Webhook) GetTemplateData(ctx context.Context, ref *esv1beta1.ExternalSecretDataRemoteRef, secrets []Secret) (map[string]map[string]string, error) {
+func (w *Webhook) GetTemplateData(ctx context.Context, ref *esv1beta1.ExternalSecretDataRemoteRef, secrets []Secret, urlEncode bool) (map[string]map[string]string, error) {
 	data := map[string]map[string]string{}
 	if ref != nil {
-		data["remoteRef"] = map[string]string{
-			"key":      url.QueryEscape(ref.Key),
-			"version":  url.QueryEscape(ref.Version),
-			"property": url.QueryEscape(ref.Property),
+		if urlEncode {
+			data["remoteRef"] = map[string]string{
+				"key":      url.QueryEscape(ref.Key),
+				"version":  url.QueryEscape(ref.Version),
+				"property": url.QueryEscape(ref.Property),
+			}
+		} else {
+			data["remoteRef"] = map[string]string{
+				"key":      ref.Key,
+				"version":  ref.Version,
+				"property": ref.Property,
+			}
 		}
 	}
 	for _, secref := range secrets {
@@ -144,19 +152,25 @@ func (w *Webhook) GetWebhookData(ctx context.Context, provider *Spec, ref *esv1b
 	if w.HTTP == nil {
 		return nil, fmt.Errorf("http client not initialized")
 	}
-	data, err := w.GetTemplateData(ctx, ref, provider.Secrets)
+
+	escapedData, err := w.GetTemplateData(ctx, ref, provider.Secrets, true)
 	if err != nil {
 		return nil, err
 	}
+	rawData, err := w.GetTemplateData(ctx, ref, provider.Secrets, false)
+	if err != nil {
+		return nil, err
+	}
+
 	method := provider.Method
 	if method == "" {
 		method = http.MethodGet
 	}
-	url, err := ExecuteTemplateString(provider.URL, data)
+	url, err := ExecuteTemplateString(provider.URL, escapedData)
 	if err != nil {
 		return nil, fmt.Errorf("failed to parse url: %w", err)
 	}
-	body, err := ExecuteTemplate(provider.Body, data)
+	body, err := ExecuteTemplate(provider.Body, rawData)
 	if err != nil {
 		return nil, fmt.Errorf("failed to parse body: %w", err)
 	}
@@ -166,7 +180,7 @@ func (w *Webhook) GetWebhookData(ctx context.Context, provider *Spec, ref *esv1b
 		return nil, fmt.Errorf("failed to create request: %w", err)
 	}
 	for hKey, hValueTpl := range provider.Headers {
-		hValue, err := ExecuteTemplateString(hValueTpl, data)
+		hValue, err := ExecuteTemplateString(hValueTpl, rawData)
 		if err != nil {
 			return nil, fmt.Errorf("failed to parse header %s: %w", hKey, err)
 		}

+ 1 - 1
pkg/provider/webhook/webhook.go

@@ -133,7 +133,7 @@ func (w *WebHook) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDat
 		return nil, err
 	}
 	// Only parse as json if we have a jsonpath set
-	data, err := w.wh.GetTemplateData(ctx, &ref, provider.Secrets)
+	data, err := w.wh.GetTemplateData(ctx, &ref, provider.Secrets, false)
 	if err != nil {
 		return nil, err
 	}

+ 16 - 0
pkg/provider/webhook/webhook_test.go

@@ -51,6 +51,7 @@ type args struct {
 
 type want struct {
 	Path      string            `json:"path,omitempty"`
+	Body      string            `json:"body,omitempty"`
 	Err       string            `json:"err,omitempty"`
 	Result    string            `json:"result,omitempty"`
 	ResultMap map[string]string `json:"resultmap,omitempty"`
@@ -327,6 +328,15 @@ want:
     alsosecret: another-value
     id: 1234
     weight: 1.5
+---
+case: only url encoding for url templates
+args:
+  url: /api/getsecrets?folder={{ .remoteRef.key }}
+  body: '{"folder": "{{ .remoteRef.key }}"}'
+  key: /myapp/secrets
+want:
+  path: /api/getsecrets?folder=%2Fmyapp%2Fsecrets
+  body: '{"folder": "/myapp/secrets"}'
 `
 
 func TestWebhookGetSecret(t *testing.T) {
@@ -349,6 +359,12 @@ func testCaseServer(tc testCase, t *testing.T) *httptest.Server {
 		if tc.Want.Path != "" && req.URL.String() != tc.Want.Path {
 			t.Errorf("%s: unexpected api path: %s, expected %s", tc.Case, req.URL.String(), tc.Want.Path)
 		}
+		if tc.Want.Body != "" {
+			b, _ := io.ReadAll(req.Body)
+			if string(b) != tc.Want.Body {
+				t.Errorf("%s: unexpected body: %s, expected %s", tc.Case, string(b), tc.Want.Body)
+			}
+		}
 		if tc.Args.StatusCode != 0 {
 			rw.WriteHeader(tc.Args.StatusCode)
 		}