Skip to content

Commit

Permalink
E2E tests for backend security (#85)
Browse files Browse the repository at this point in the history
* Added e2e tests

Signed-off-by: Ali Ok <[email protected]>

* Check in vendored files

Signed-off-by: Ali Ok <[email protected]>

* Actually run the tests

Signed-off-by: Ali Ok <[email protected]>

* goimports

Signed-off-by: Ali Ok <[email protected]>

---------

Signed-off-by: Ali Ok <[email protected]>
  • Loading branch information
aliok authored Sep 19, 2024
1 parent 00059a3 commit 08f8689
Show file tree
Hide file tree
Showing 9 changed files with 491 additions and 3 deletions.
66 changes: 64 additions & 2 deletions backends/tests/e2e/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,71 @@
package e2e

import (
"context"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeclient "knative.dev/pkg/client/injection/kube/client"
"knative.dev/reconciler-test/pkg/k8s"
"knative.dev/reconciler-test/pkg/knative"

"knative.dev/reconciler-test/pkg/environment"
"knative.dev/reconciler-test/pkg/eventshub"
"knative.dev/reconciler-test/pkg/eventshub/assert"
"knative.dev/reconciler-test/pkg/feature"
)

func TestSample(t *testing.T) {
t.Log("All good")
func TestIntegration(t *testing.T) {
t.Parallel()

ctx, env := global.Environment(
knative.WithKnativeNamespace("knative-eventing"),
knative.WithLoggingConfig,
knative.WithTracingConfig,
k8s.WithEventListener,
environment.Managed(t),
)
env.Test(ctx, t, VerifyBackstageBackendAuthentication())
}

func VerifyBackstageBackendAuthentication() *feature.Feature {

f := feature.NewFeature()

authenticatedClientName := feature.MakeRandomK8sName("authenticated-client")
unauthenticatedClientName := feature.MakeRandomK8sName("unauthenticated-client")
SANamespace := "eventmesh-backend-user-namespace"
SecretName := "eventmesh-backend-user-secret"

f.Setup("request with authenticated client", func(ctx context.Context, t feature.T) {
secret, err := kubeclient.Get(ctx).CoreV1().Secrets(SANamespace).Get(ctx, SecretName, metav1.GetOptions{})
if err != nil {
t.Fatal("Failed to get secret", err)
}

token := string(secret.Data["token"])

eventshub.Install(authenticatedClientName,
eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080"),
eventshub.InputHeader("Authorization", "Bearer "+token),
eventshub.InputMethod("GET"),
)(ctx, t)
})
f.Setup("request with unauthenticated client", eventshub.Install(
unauthenticatedClientName,
eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080"),
eventshub.InputHeader("Foo", "Bar"),
eventshub.InputMethod("GET")),
)

f.Assert("assert response with authenticated client", assert.OnStore(authenticatedClientName).
Match(assert.MatchKind(eventshub.EventResponse)).
Match(assert.MatchStatusCode(200)).
AtLeast(1))
f.Assert("assert response with unauthenticated client", assert.OnStore(unauthenticatedClientName).
Match(assert.MatchKind(eventshub.EventResponse)).
Match(assert.MatchStatusCode(401)).
AtLeast(1))

return f
}
41 changes: 41 additions & 0 deletions backends/tests/e2e/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//go:build e2e
// +build e2e

/*
* Copyright 2024 The Knative Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package e2e

import (
"os"
"testing"

_ "knative.dev/pkg/system/testing"
"knative.dev/reconciler-test/pkg/environment"
)

// global is the singleton instance of GlobalEnvironment. It is used to parse
// the testing config for the test run. The config will specify the cluster
// config as well as the parsing level and state flags.
var global environment.GlobalEnvironment

// TestMain is the first entry point for `go test`.
func TestMain(m *testing.M) {
global = environment.NewStandardGlobalEnvironment()

// Run the tests.
os.Exit(m.Run())
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
knative.dev/eventing v0.39.1
knative.dev/hack v0.0.0-20231122182901-eb352426ecc1
knative.dev/pkg v0.0.0-20231204120332-9386ad6703ee
knative.dev/reconciler-test v0.0.0-20231024072442-5fb93a792b99
)

require (
Expand Down Expand Up @@ -103,7 +104,6 @@ require (
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
knative.dev/reconciler-test v0.0.0-20231024072442-5fb93a792b99 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions hack/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ import (
_ "knative.dev/eventing/hack"
_ "knative.dev/hack"
_ "knative.dev/pkg/hack"

// eventshub is a cloudevents sender/receiver utility for e2e testing.
_ "knative.dev/reconciler-test/cmd/eventshub"
)
72 changes: 72 additions & 0 deletions test/config/eventmesh-backend-user.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright 2024 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Namespace
metadata:
name: eventmesh-backend-user-namespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: eventmesh-backend-user-service-account
namespace: eventmesh-backend-user-namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: eventmesh-backend-user-cluster-role
rules:
# permissions for eventtypes, brokers and triggers
- apiGroups:
- "eventing.knative.dev"
resources:
- brokers
- eventtypes
- triggers
verbs:
- get
- list
- watch
# permissions to get subscribers for triggers
# as subscribers can be any resource, we need to give access to all resources
# we fetch subscribers one by one, we only need `get` verb
- apiGroups:
- "*"
resources:
- "*"
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: eventmesh-backend-user-cluster-role-binding
subjects:
- kind: ServiceAccount
name: eventmesh-backend-user-service-account
namespace: eventmesh-backend-user-namespace
roleRef:
kind: ClusterRole
name: eventmesh-backend-user-cluster-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Secret
metadata:
name: eventmesh-backend-user-secret
namespace: eventmesh-backend-user-namespace
annotations:
kubernetes.io/service-account.name: eventmesh-backend-user-service-account
type: kubernetes.io/service-account-token
20 changes: 20 additions & 0 deletions vendor/knative.dev/reconciler-test/pkg/eventshub/assert/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
Copyright 2021 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
assert contains the necessary matchers and steps to perform assertions on eventshub contents
*/
package assert
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
Copyright 2020 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package assert

import (
"fmt"
"strings"

cloudevents "github.com/cloudevents/sdk-go/v2"
cetest "github.com/cloudevents/sdk-go/v2/test"

"knative.dev/reconciler-test/pkg/eventshub"
)

// Matcher that never fails
func Any() eventshub.EventInfoMatcher {
return func(ei eventshub.EventInfo) error {
return nil
}
}

// Matcher that fails if there is an error in the EventInfo
func NoError() eventshub.EventInfoMatcher {
return func(ei eventshub.EventInfo) error {
if ei.Error != "" {
return fmt.Errorf("not expecting an error in event info: %s", ei.Error)
}
return nil
}
}

// Convert a matcher that checks valid messages to a function
// that checks EventInfo structures, returning an error for any that don't
// contain valid events.
func MatchEvent(evf ...cetest.EventMatcher) eventshub.EventInfoMatcher {
return func(ei eventshub.EventInfo) error {
if ei.Event == nil {
return fmt.Errorf("Saw nil event")
} else {
return cetest.AllOf(evf...)(*ei.Event)
}
}
}

// Convert a matcher that checks valid messages to a function
// that checks EventInfo structures, returning an error for any that don't
// contain valid events.
func HasAdditionalHeader(key, value string) eventshub.EventInfoMatcher {
key = strings.ToLower(key)
return func(ei eventshub.EventInfo) error {
for k, v := range ei.HTTPHeaders {
if strings.ToLower(k) == key && v[0] == value {
return nil
}
}
return fmt.Errorf("cannot find header '%s' = '%s' between the headers", key, value)
}
}

// Reexport kinds here to simplify the usage
const (
EventReceived = eventshub.EventReceived
EventRejected = eventshub.EventRejected

EventSent = eventshub.EventSent
EventResponse = eventshub.EventResponse
)

// MatchKind matches the kind of EventInfo
func MatchKind(kind eventshub.EventKind) eventshub.EventInfoMatcher {
return func(info eventshub.EventInfo) error {
if kind != info.Kind {
return fmt.Errorf("event kind don't match. Expected: '%s', Actual: '%s'", kind, info.Kind)
}
return nil
}
}

func OneOf(matchers ...eventshub.EventInfoMatcher) eventshub.EventInfoMatcher {
return func(info eventshub.EventInfo) error {
var lastErr error
for _, m := range matchers {
err := m(info)
if err == nil {
return nil
}
lastErr = err
}
return lastErr
}
}

// MatchStatusCode matches the status code of EventInfo
func MatchStatusCode(statusCode int) eventshub.EventInfoMatcher {
return func(info eventshub.EventInfo) error {
if info.StatusCode != statusCode {
return fmt.Errorf("event status code don't match. Expected: '%d', Actual: '%d'", statusCode, info.StatusCode)
}
return nil
}
}

// MatchHeartBeatsImageMessage matches that the data field of the event, in the format of the heartbeats image, contains the following msg field
func MatchHeartBeatsImageMessage(expectedMsg string) cetest.EventMatcher {
return cetest.AllOf(
cetest.HasDataContentType(cloudevents.ApplicationJSON),
func(have cloudevents.Event) error {
var m map[string]interface{}
err := have.DataAs(&m)
if err != nil {
return fmt.Errorf("cannot parse heartbeats message %s", err.Error())
}
if m["msg"].(string) != expectedMsg {
return fmt.Errorf("heartbeats message don't match. Expected: '%s', Actual: '%s'", expectedMsg, m["msg"].(string))
}
return nil
},
)
}
Loading

0 comments on commit 08f8689

Please sign in to comment.