Skip to content

Commit

Permalink
OSSM-8251: Add test for file upload case (#753)
Browse files Browse the repository at this point in the history
  • Loading branch information
unsortedhashsets authored Oct 16, 2024
1 parent 20a3703 commit 4623dc6
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 44 deletions.
29 changes: 15 additions & 14 deletions pkg/app/sleep.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/pod"
"github.com/maistra/maistra-test-tool/pkg/util/retry"
"github.com/maistra/maistra-test-tool/pkg/util/test"

. "github.com/maistra/maistra-test-tool/pkg/util/test"
)

type sleep struct {
Expand Down Expand Up @@ -66,17 +67,17 @@ func (a *sleep) Namespace() string {
return a.ns
}

func (a *sleep) Install(t test.TestHelper) {
func (a *sleep) Install(t TestHelper) {
t.T().Helper()
oc.ApplyTemplate(t, a.ns, sleepTemplate, a.values(t))
}

func (a *sleep) Uninstall(t test.TestHelper) {
func (a *sleep) Uninstall(t TestHelper) {
t.T().Helper()
oc.DeleteFromTemplate(t, a.ns, sleepTemplate, a.values(t))
}

func (a *sleep) values(t test.TestHelper) map[string]interface{} {
func (a *sleep) values(t TestHelper) map[string]interface{} {
proxy := oc.GetProxy(t)
return map[string]interface{}{
"InjectSidecar": a.injectSidecar,
Expand All @@ -90,7 +91,7 @@ func (a *sleep) values(t test.TestHelper) map[string]interface{} {
}
}

func (a *sleep) WaitReady(t test.TestHelper) {
func (a *sleep) WaitReady(t TestHelper) {
t.T().Helper()
oc.WaitDeploymentRolloutComplete(t, a.ns, "sleep")
}
Expand All @@ -101,35 +102,35 @@ type CurlOpts struct {
Options []string
}

func ExecInSleepPod(t test.TestHelper, ns string, command string, checks ...common.CheckFunc) {
func ExecInSleepPod(t TestHelper, ns string, command string, checks ...common.CheckFunc) {
t.T().Helper()
retry.UntilSuccess(t, func(t test.TestHelper) {
retry.UntilSuccessWithOptions(t, retry.Options().MaxAttempts(10), func(t TestHelper) {
t.T().Helper()
oc.Exec(t, pod.MatchingSelector("app=sleep", ns), "sleep", command, checks...)
})
}

func AssertSleepPodRequestSuccess(t test.TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
func AssertSleepPodRequestSuccess(t TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
assertSleepPodRequestResponse(t, sleepNamespace, url, "200", opts...)
}

func AssertSleepPodRequestFailure(t test.TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
func AssertSleepPodRequestFailure(t TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
assertSleepPodRequestResponse(t, sleepNamespace, url, curlFailedMessage, opts...)
}

func AssertSleepPodRequestForbidden(t test.TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
func AssertSleepPodRequestForbidden(t TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
assertSleepPodRequestResponse(t, sleepNamespace, url, "403", opts...)
}

func AssertSleepPodRequestUnauthorized(t test.TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
func AssertSleepPodRequestUnauthorized(t TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
assertSleepPodRequestResponse(t, sleepNamespace, url, "401", opts...)
}

func AssertSleepPodZeroesPlaceholder(t test.TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
func AssertSleepPodZeroesPlaceholder(t TestHelper, sleepNamespace string, url string, opts ...CurlOpts) {
assertSleepPodRequestResponse(t, sleepNamespace, url, "000", opts...)
}

func assertSleepPodRequestResponse(t test.TestHelper, sleepNamespace, url, expected string, opts ...CurlOpts) {
func assertSleepPodRequestResponse(t TestHelper, sleepNamespace, url, expected string, opts ...CurlOpts) {
command := buildCurlCmd(url, opts...)
ExecInSleepPod(t, sleepNamespace, command,
assert.OutputContains(expected,
Expand Down Expand Up @@ -162,7 +163,7 @@ func buildCurlCmd(url string, opts ...CurlOpts) string {
}
}

return fmt.Sprintf(`curl -sS %s%s -X %s -o /dev/null -w "%%{http_code}" %s 2>/dev/null || echo %s`, options, headers, method, url, curlFailedMessage)
return fmt.Sprintf(`curl -sS%s%s -X %s -o /dev/null -w "%%{http_code}" %s 2>/dev/null || echo %s`, headers, options, method, url, curlFailedMessage)
}

const curlFailedMessage = "CURL_FAILED"
Expand Down
122 changes: 92 additions & 30 deletions pkg/tests/tasks/security/authorization/ext_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,44 @@
package authorization

import (
"fmt"
"testing"

"github.com/maistra/maistra-test-tool/pkg/app"
"github.com/maistra/maistra-test-tool/pkg/tests/ossm"
"github.com/maistra/maistra-test-tool/pkg/util/env"
"github.com/maistra/maistra-test-tool/pkg/util/ns"
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/test"
"github.com/maistra/maistra-test-tool/pkg/util/version"

. "github.com/maistra/maistra-test-tool/pkg/util/test"
)

func TestEnvoyExtAuthzHttpExtensionProvider(t *testing.T) {
test.NewTest(t).Id("T37").Groups(test.Full, test.InterOp, test.ARM).Run(func(t test.TestHelper) {
NewTest(t).Id("T37").Groups(Full, InterOp, ARM).Run(func(t TestHelper) {
if env.GetSMCPVersion().LessThan(version.SMCP_2_3) {
t.Skip("extensionProviders.envoyExtAuthzHttp was added in v2.3")
}
t.Log("This test validates authorization policies with a JWT Token")

ns := "foo"

ossm.DeployControlPlane(t)

t.LogStep("Install httpbin and sleep")
app.InstallAndWaitReady(t, app.Httpbin(ns), app.Sleep(ns))
app.InstallAndWaitReady(t, app.Httpbin(ns.Foo), app.Sleep(ns.Foo))
t.Cleanup(func() {
app.Uninstall(t, app.Httpbin(ns), app.Sleep(ns))
app.Uninstall(t, app.Httpbin(ns.Foo), app.Sleep(ns.Foo))
})

t.LogStep("Check if httpbin returns 200 OK when no authorization policies are in place")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/ip")
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/ip")

t.LogStep("Deploy the External Authorizer and Verify the sample external authorizer is up and running")
oc.ApplyTemplate(t, ns, ExternalAuthzService, nil)
oc.ApplyTemplate(t, ns.Foo, ExternalAuthzService, nil)
t.Cleanup(func() {
oc.DeleteFromTemplate(t, ns, ExternalAuthzService, nil)
oc.DeleteFromTemplate(t, ns.Foo, ExternalAuthzService, nil)
})

oc.WaitDeploymentRolloutComplete(t, ns, "ext-authz")
oc.WaitDeploymentRolloutComplete(t, ns.Foo, "ext-authz")

t.LogStep("Set envoyExtAuthzHttp extension provider in SMCP")
if env.GetSMCPVersion().LessThan(version.SMCP_2_4) {
Expand Down Expand Up @@ -120,48 +121,46 @@ spec:

t.LogStep("Deploy the external authorization in the Authorization policy")
t.Cleanup(func() {
oc.DeleteFromString(t, ns, ExternalRoute)
oc.DeleteFromString(t, ns.Foo, ExternalRoute)
})
oc.ApplyString(t, ns, ExternalRoute)
oc.ApplyString(t, ns.Foo, ExternalRoute)

t.LogStep("Verify a request to path /headers with header x-ext-authz: deny is denied by the sample ext_authz server:")
app.AssertSleepPodRequestForbidden(t, ns, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: deny"}})
app.AssertSleepPodRequestForbidden(t, ns.Foo, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: deny"}})

t.LogStep("Verify a request to path /headers with header x-ext-authz: allow is allowed by the sample ext_authz server")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: allow"}})
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: allow"}})

t.LogStep("Verify a request to path /ip is allowed and does not trigger the external authorization")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/ip")
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/ip")
})
}

func TestEnvoyExtAuthzGrpcExtensionProvider(t *testing.T) {
test.NewTest(t).Id("T42").Groups(test.Full, test.InterOp, test.ARM).Run(func(t test.TestHelper) {
NewTest(t).Id("T42").Groups(Full, InterOp, ARM).Run(func(t TestHelper) {
if env.GetSMCPVersion().LessThan(version.SMCP_2_3) {
t.Skip("extensionProviders.envoyExtAuthzGrpc is not supported in versions below v2.3")
}
t.Log("This test validates authorization policies with a JWT Token")

ns := "foo"

ossm.DeployControlPlane(t)

t.LogStep("Install httpbin and sleep")
app.InstallAndWaitReady(t, app.Httpbin(ns), app.Sleep(ns))
app.InstallAndWaitReady(t, app.Httpbin(ns.Foo), app.Sleep(ns.Foo))
t.Cleanup(func() {
app.Uninstall(t, app.Httpbin(ns), app.Sleep(ns))
app.Uninstall(t, app.Httpbin(ns.Foo), app.Sleep(ns.Foo))
})

t.LogStep("Check if httpbin returns 200 OK when no authorization policies are in place")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/ip")
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/ip")

t.LogStep("Deploy the External Authorizer and Verify the sample external authorizer is up and running")
oc.ApplyTemplate(t, ns, ExternalAuthzService, nil)
oc.ApplyTemplate(t, ns.Foo, ExternalAuthzService, nil)
t.Cleanup(func() {
oc.DeleteFromTemplate(t, ns, ExternalAuthzService, nil)
oc.DeleteFromTemplate(t, ns.Foo, ExternalAuthzService, nil)
})

oc.WaitDeploymentRolloutComplete(t, ns, "ext-authz")
oc.WaitDeploymentRolloutComplete(t, ns.Foo, "ext-authz")

t.LogStep("Set envoyExtAuthzgRPC extension provider in SMCP")
if env.GetSMCPVersion().LessThan(version.SMCP_2_4) {
Expand Down Expand Up @@ -202,21 +201,84 @@ spec:

t.LogStep("Deploy the external authorization in the Authorization policy")
t.Cleanup(func() {
oc.DeleteFromString(t, ns, ExternalRouteGrpc)
oc.DeleteFromString(t, ns.Foo, ExternalRouteGrpc)
})
oc.ApplyString(t, ns, ExternalRouteGrpc)
oc.ApplyString(t, ns.Foo, ExternalRouteGrpc)

t.LogStep("Verify a request to path /headers with header x-ext-authz: deny is denied by the sample ext_authz server:")
app.AssertSleepPodRequestForbidden(t, ns, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: deny"}})
app.AssertSleepPodRequestForbidden(t, ns.Foo, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: deny"}})

t.LogStep("Verify a request to path /headers with header x-ext-authz: allow is allowed by the sample ext_authz server")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: allow"}})
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/headers", app.CurlOpts{Headers: []string{"x-ext-authz: allow"}})

t.LogStep("Verify a request to path /ip is allowed and does not trigger the external authorization")
app.AssertSleepPodRequestSuccess(t, ns, "http://httpbin:8000/ip")
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/ip")
})
}

func TestEnvoyExtAuthzRequestPayloadTooLarge(t *testing.T) {
NewTest(t).Groups(Full, Disconnected, ARM).Run(func(t TestHelper) {
t.Log("Verify that Istio proxy doesn't fail with 'Request payload too large' error")
t.Log("Reference: https://issues.redhat.com/browse/OSSM-5850")

t.Cleanup(func() {
oc.RecreateNamespace(t, ns.Foo, meshNamespace)
})

ossm.DeployControlPlane(t)

t.LogStep("Install httpbin and sleep")
app.InstallAndWaitReady(t,
app.Httpbin(ns.Foo),
app.Sleep(ns.Foo))

t.LogStep("Create 2MB file in the sleep pod")
app.ExecInSleepPod(t, ns.Foo, "fallocate -l 2M /tmp/fakefile_2MB")
assertFileUploadSuccess(t)

t.LogStep("Deploy the External Authorizer and Verify the sample external authorizer is up and running")
oc.ApplyTemplate(t, ns.Foo, ExternalAuthzService, nil)
oc.WaitDeploymentRolloutComplete(t, ns.Foo, "ext-authz")

t.LogStep("Deploy the external authorization in the Authorization policy")
oc.ApplyString(t, ns.Foo, ExternalRoute)

t.LogStep("Patch SMCP to enable envoyExtAuthzHttp with allowPartialMessage true and maxRequestBytes 1KB")
oc.Patch(t, meshNamespace, "smcp", smcpName, "merge", uploadEnvoyExtSpec("true", 1024))
oc.WaitSMCPReady(t, meshNamespace, smcpName)
assertFileUploadSuccess(t)

t.LogStep("Patch SMCP to set allowPartialMessage to false and increase maxRequestBytes to 5MB")
oc.Patch(t, meshNamespace, "smcp", smcpName, "merge", uploadEnvoyExtSpec("false", 5000000))
oc.WaitSMCPReady(t, meshNamespace, smcpName)
assertFileUploadSuccess(t)
})
}

func assertFileUploadSuccess(t TestHelper) {
t.LogStep("Send a POST request with a large file (2MB)")
app.AssertSleepPodRequestSuccess(t, ns.Foo, "http://httpbin:8000/post", app.CurlOpts{
Method: "POST",
Headers: []string{"x-ext-authz: allow", "Content-Type: multipart/form-data"},
Options: []string{"-F file=@/tmp/fakefile_2MB"}})
}

func uploadEnvoyExtSpec(AllowPartialMessage string, MaxRequestBytes int) string {
return fmt.Sprintf(`
spec:
meshConfig:
extensionProviders:
- name: sample-ext-authz-http
envoyExtAuthzHttp:
service: ext-authz.foo.svc.cluster.local
port: 8000
includeRequestHeadersInCheck: ["x-ext-authz"]
includeRequestBodyInCheck:
allowPartialMessage: %s
maxRequestBytes: %d
packAsBytes: true`, AllowPartialMessage, MaxRequestBytes)
}

const (
ExternalRoute = `
apiVersion: security.istio.io/v1beta1
Expand All @@ -237,7 +299,7 @@ spec:
# The rules specify when to trigger the external authorizer.
- to:
- operation:
paths: ["/headers"]
paths: ["/headers", "/post"]
`
ExternalRouteGrpc = `
apiVersion: security.istio.io/v1beta1
Expand Down

0 comments on commit 4623dc6

Please sign in to comment.