Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/http/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ func AuthorizationMiddleware(requireOAuth bool, serverURL string, oidcProvider *
klog.V(1).Infof("Authentication failed - missing or invalid bearer token: %s %s from %s", r.Method, r.URL.Path, r.RemoteAddr)

if serverURL == "" {
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="Kubernetes MCP Server", audience="%s", error="invalid_token"`, audience))
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="Kubernetes MCP Server", audience="%s", error="missing_token"`, audience))
} else {
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="Kubernetes MCP Server", audience="%s"", resource_metadata="%s%s", error="invalid_token"`, audience, serverURL, oauthProtectedResourceEndpoint))
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="Kubernetes MCP Server", audience="%s"", resource_metadata="%s%s", error="missing_token"`, audience, serverURL, oauthProtectedResourceEndpoint))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ardaguclu I'm not sure if this might be problematic with any of the client usages you've tried. This allows us to have more granular tracing (client+testing-side) of where the token validation failed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks good to me.

}
http.Error(w, "Unauthorized: Bearer token required", http.StatusUnauthorized)
return
Expand Down Expand Up @@ -103,7 +103,7 @@ func AuthorizationMiddleware(requireOAuth bool, serverURL string, oidcProvider *
// with the other token in the headers (TODO: still need to validate aud and exp of this token separately).
_, _, err = mcpServer.VerifyTokenAPIServer(r.Context(), token, audience)
if err != nil {
klog.V(1).Infof("Authentication failed - token validation error: %s %s from %s, error: %v", r.Method, r.URL.Path, r.RemoteAddr, err)
klog.V(1).Infof("Authentication failed - API Server token validation error: %s %s from %s, error: %v", r.Method, r.URL.Path, r.RemoteAddr, err)

if serverURL == "" {
w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer realm="Kubernetes MCP Server", audience="%s", error="invalid_token"`, audience))
Expand Down
102 changes: 0 additions & 102 deletions pkg/http/authorization_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package http

import (
"net/http"
"net/http/httptest"
"strings"
"testing"

Expand Down Expand Up @@ -220,103 +218,3 @@ func TestJWTClaimsGetScopes(t *testing.T) {
}
})
}

func TestAuthorizationMiddleware(t *testing.T) {
// Create a mock handler
handlerCalled := false
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handlerCalled = true
w.WriteHeader(http.StatusOK)
})

t.Run("OAuth disabled - passes through", func(t *testing.T) {
handlerCalled = false

// Create middleware with OAuth disabled
middleware := AuthorizationMiddleware(false, "", nil, nil)
wrappedHandler := middleware(handler)

// Create request without authorization header
req := httptest.NewRequest("GET", "/test", nil)
w := httptest.NewRecorder()

wrappedHandler.ServeHTTP(w, req)

if !handlerCalled {
t.Error("expected handler to be called when OAuth is disabled")
}
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d", w.Code)
}
})

t.Run("healthz endpoint - passes through", func(t *testing.T) {
handlerCalled = false

// Create middleware with OAuth enabled
middleware := AuthorizationMiddleware(true, "", nil, nil)
wrappedHandler := middleware(handler)

// Create request to healthz endpoint
req := httptest.NewRequest("GET", "/healthz", nil)
w := httptest.NewRecorder()

wrappedHandler.ServeHTTP(w, req)

if !handlerCalled {
t.Error("expected handler to be called for healthz endpoint")
}
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d", w.Code)
}
})

t.Run("OAuth enabled - missing token", func(t *testing.T) {
handlerCalled = false

// Create middleware with OAuth enabled
middleware := AuthorizationMiddleware(true, "", nil, nil)
wrappedHandler := middleware(handler)

// Create request without authorization header
req := httptest.NewRequest("GET", "/test", nil)
w := httptest.NewRecorder()

wrappedHandler.ServeHTTP(w, req)

if handlerCalled {
t.Error("expected handler NOT to be called when token is missing")
}
if w.Code != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", w.Code)
}
if !strings.Contains(w.Body.String(), "Bearer token required") {
t.Errorf("expected bearer token error message, got %s", w.Body.String())
}
})

t.Run("OAuth enabled - invalid token format", func(t *testing.T) {
handlerCalled = false

// Create middleware with OAuth enabled
middleware := AuthorizationMiddleware(true, "", nil, nil)
wrappedHandler := middleware(handler)

// Create request with invalid bearer token
req := httptest.NewRequest("GET", "/test", nil)
req.Header.Set("Authorization", "Bearer invalid-token")
w := httptest.NewRecorder()

wrappedHandler.ServeHTTP(w, req)

if handlerCalled {
t.Error("expected handler NOT to be called when token is invalid")
}
if w.Code != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", w.Code)
}
if !strings.Contains(w.Body.String(), "Invalid token") {
t.Errorf("expected invalid token error message, got %s", w.Body.String())
}
})
}
Loading
Loading