Previously BearerMiddleware allowed requests with no Authorization header to pass through whenever GITEA_MCP_DEFAULT_TOKEN was set. The intent was "fall back to the service PAT for upstream Gitea calls," but the side effect was that anyone could hit /mcp anonymously and the server would happily proxy requests as the service account. Drop that path. Auth on /mcp now requires either: - a valid Dex-issued JWT, or - a Bearer matching GITEA_MCP_STATIC_TOKEN. The Gitea service PAT (GITEA_MCP_DEFAULT_TOKEN) is no longer wired into BearerMiddleware at all — it stays an upstream-client concern, used by gitea.NewClient for outbound API calls only. This decouples "can this caller invoke a tool" from "what credentials does the tool use against Gitea". Tests updated: drop the NoAuthHeader_WithDefault permissive case, add NoAuthHeader_RejectsEvenWhenStaticConfigured to lock in the new behavior. Closes part of mathias/infra#2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
93 lines
3.0 KiB
Go
93 lines
3.0 KiB
Go
package auth_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"gitea.d-ma.be/mathias/gitea-mcp/internal/auth"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func okHandler(called *bool) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
if called != nil {
|
|
*called = true
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
}
|
|
|
|
func TestBearerMiddleware_NoAuthHeader(t *testing.T) {
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, "", okHandler(nil)))
|
|
defer srv.Close()
|
|
|
|
resp, err := http.Post(srv.URL+"/mcp", "application/json", nil)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
}
|
|
|
|
func TestBearerMiddleware_NoAuthHeader_RejectsEvenWhenStaticConfigured(t *testing.T) {
|
|
// A configured staticToken must not allow unauthenticated callers through.
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, "any-static", okHandler(nil)))
|
|
defer srv.Close()
|
|
|
|
resp, err := http.Post(srv.URL+"/mcp", "application/json", nil)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
}
|
|
|
|
func TestBearerMiddleware_EmptyBearer(t *testing.T) {
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, "static", okHandler(nil)))
|
|
defer srv.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, srv.URL+"/mcp", nil)
|
|
req.Header.Set("Authorization", "Bearer ")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
}
|
|
|
|
func TestBearerMiddleware_StaticToken_Valid(t *testing.T) {
|
|
const staticToken = "my-static-token"
|
|
called := false
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, staticToken, okHandler(&called)))
|
|
defer srv.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, srv.URL+"/mcp", nil)
|
|
req.Header.Set("Authorization", "Bearer "+staticToken)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
assert.True(t, called)
|
|
}
|
|
|
|
func TestBearerMiddleware_StaticToken_Invalid(t *testing.T) {
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, "correct-token", okHandler(nil)))
|
|
defer srv.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, srv.URL+"/mcp", nil)
|
|
req.Header.Set("Authorization", "Bearer wrong-token")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
}
|
|
|
|
func TestBearerMiddleware_UnknownBearer_NoStatic_NoJWT(t *testing.T) {
|
|
srv := httptest.NewServer(auth.BearerMiddleware(nil, "", okHandler(nil)))
|
|
defer srv.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, srv.URL+"/mcp", nil)
|
|
req.Header.Set("Authorization", "Bearer random-unknown-token")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer func() { _ = resp.Body.Close() }()
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
}
|