-
Notifications
You must be signed in to change notification settings - Fork 221
Expand file tree
/
Copy pathmiddleware_test.go
More file actions
246 lines (186 loc) · 6.68 KB
/
middleware_test.go
File metadata and controls
246 lines (186 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0
package auth
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/stacklok/toolhive/pkg/transport/types"
"github.com/stacklok/toolhive/pkg/transport/types/mocks"
)
func TestMiddleware_Handler(t *testing.T) {
t.Parallel()
// Create a mock middleware function
mockMiddlewareFunc := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Test", "middleware-called")
next.ServeHTTP(w, r)
})
}
// Create middleware instance
middleware := &Middleware{
middleware: mockMiddlewareFunc,
}
// Test that Handler returns the correct middleware function
handlerFunc := middleware.Handler()
// Create a test handler to wrap
testHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("test response"))
})
// Wrap the test handler with the middleware
wrappedHandler := handlerFunc(testHandler)
// Test the wrapped handler
req := httptest.NewRequest("GET", "/test", nil)
w := httptest.NewRecorder()
wrappedHandler.ServeHTTP(w, req)
// Verify the middleware was called
assert.Equal(t, "middleware-called", w.Header().Get("X-Test"))
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "test response", w.Body.String())
}
func TestMiddleware_Close(t *testing.T) {
t.Parallel()
middleware := &Middleware{}
// Test that Close returns nil (no cleanup needed)
err := middleware.Close()
assert.NoError(t, err)
}
func TestMiddleware_AuthInfoHandler(t *testing.T) {
t.Parallel()
// Create a mock auth info handler
mockHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("auth info"))
})
middleware := &Middleware{
authInfoHandler: mockHandler,
}
// Test that AuthInfoHandler returns the correct handler
handler := middleware.AuthInfoHandler()
// Test the handler
req := httptest.NewRequest("GET", "/.well-known/oauth-protected-resource", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "auth info", w.Body.String())
}
func TestCreateMiddleware_WithoutOIDCConfig(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// Create mock runner
mockRunner := mocks.NewMockMiddlewareRunner(ctrl)
// Expect GetUpstreamTokenReader and GetKeyProvider to be called (returns nil = no auth server)
mockRunner.EXPECT().GetUpstreamTokenReader().Return(nil)
mockRunner.EXPECT().GetKeyProvider().Return(nil)
// Expect AddMiddleware to be called with a middleware instance
mockRunner.EXPECT().AddMiddleware(gomock.Any(), gomock.Any()).Do(func(name string, mw types.Middleware) {
// Verify it's our auth middleware
_, ok := mw.(*Middleware)
assert.True(t, ok, "Expected middleware to be of type *auth.Middleware")
assert.Equal(t, MiddlewareType, name, "Expected middleware name to be 'auth'")
})
// Create parameters without OIDC config (local auth)
params := MiddlewareParams{}
paramsJSON, err := json.Marshal(params)
require.NoError(t, err)
config := &types.MiddlewareConfig{
Type: MiddlewareType,
Parameters: paramsJSON,
}
// Test CreateMiddleware
err = CreateMiddleware(config, mockRunner)
assert.NoError(t, err)
}
func TestCreateMiddleware_WithOIDCConfig(t *testing.T) {
t.Skip("Skipping OIDC test - requires real OIDC discovery endpoint or complex mocking")
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// Create mock runner
mockRunner := mocks.NewMockMiddlewareRunner(ctrl)
// Create parameters with OIDC config
oidcConfig := &TokenValidatorConfig{
Issuer: "https://example.com/auth",
ResourceURL: "https://api.example.com",
}
params := MiddlewareParams{
OIDCConfig: oidcConfig,
}
paramsJSON, err := json.Marshal(params)
require.NoError(t, err)
config := &types.MiddlewareConfig{
Type: MiddlewareType,
Parameters: paramsJSON,
}
// Note: This test is skipped because NewTokenValidator requires actual OIDC discovery
// In a real test environment, you'd need to mock the OIDC discovery or use a test OIDC server
err = CreateMiddleware(config, mockRunner)
// We expect an error here because we don't have a real OIDC endpoint
// The important thing is that it gets past parameter parsing
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to create authentication middleware")
}
func TestCreateMiddleware_InvalidParameters(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRunner := mocks.NewMockMiddlewareRunner(ctrl)
// Create config with invalid JSON parameters
config := &types.MiddlewareConfig{
Type: MiddlewareType,
Parameters: []byte(`{"invalid": json`), // Invalid JSON
}
// Test CreateMiddleware with invalid parameters
err := CreateMiddleware(config, mockRunner)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to unmarshal auth middleware parameters")
}
func TestCreateMiddleware_NilParameters(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRunner := mocks.NewMockMiddlewareRunner(ctrl)
// Create config with nil parameters - this should fail during unmarshaling
config := &types.MiddlewareConfig{
Type: MiddlewareType,
Parameters: nil,
}
// This should fail because nil cannot be unmarshaled
err := CreateMiddleware(config, mockRunner)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to unmarshal auth middleware parameters")
}
func TestCreateMiddleware_EmptyParameters(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRunner := mocks.NewMockMiddlewareRunner(ctrl)
// Expect GetUpstreamTokenReader and GetKeyProvider to be called (returns nil = no auth server)
mockRunner.EXPECT().GetUpstreamTokenReader().Return(nil)
mockRunner.EXPECT().GetKeyProvider().Return(nil)
// Expect AddMiddleware to be called
mockRunner.EXPECT().AddMiddleware(gomock.Any(), gomock.Any())
// Create config with empty JSON parameters
config := &types.MiddlewareConfig{
Type: MiddlewareType,
Parameters: []byte(`{}`),
}
err := CreateMiddleware(config, mockRunner)
assert.NoError(t, err)
}
func TestMiddlewareType_Constant(t *testing.T) {
t.Parallel()
// Test that the middleware type constant is correct
assert.Equal(t, "auth", MiddlewareType)
}
func TestMiddleware_InterfaceCompliance(t *testing.T) {
t.Parallel()
// Test that Middleware implements the types.Middleware interface
var _ types.Middleware = (*Middleware)(nil)
}