@@ -10,8 +10,6 @@ import (
1010
1111 "github.com/gin-contrib/cors"
1212 "github.com/gin-gonic/gin"
13- authnv1 "k8s.io/api/authentication/v1"
14- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1513)
1614
1715// RouterFunc is a function that can register routes on a Gin router
@@ -65,11 +63,9 @@ func Run(registerRoutes RouterFunc) error {
6563 return nil
6664}
6765
68- // forwardedIdentityMiddleware populates Gin context from common OAuth proxy headers.
69- // Fallback: if OAuth headers are not present, performs TokenReview on Authorization Bearer token.
66+ // forwardedIdentityMiddleware populates Gin context from common OAuth proxy headers
7067func forwardedIdentityMiddleware () gin.HandlerFunc {
7168 return func (c * gin.Context ) {
72- // Try OAuth proxy headers first (production with oauth-proxy)
7369 if v := c .GetHeader ("X-Forwarded-User" ); v != "" {
7470 c .Set ("userID" , v )
7571 }
@@ -87,74 +83,6 @@ func forwardedIdentityMiddleware() gin.HandlerFunc {
8783 if v := c .GetHeader ("X-Forwarded-Groups" ); v != "" {
8884 c .Set ("userGroups" , strings .Split (v , "," ))
8985 }
90-
91- // Fallback: if no OAuth headers, try TokenReview on Authorization token
92- // This enables development/testing without oauth-proxy and service account auth
93- if c .GetString ("userID" ) == "" {
94- if auth := c .GetHeader ("Authorization" ); auth != "" {
95- parts := strings .SplitN (auth , " " , 2 )
96- if len (parts ) == 2 && strings .EqualFold (parts [0 ], "Bearer" ) {
97- token := strings .TrimSpace (parts [1 ])
98- if token != "" {
99- // Check if K8sClient is initialized
100- if K8sClient == nil {
101- log .Printf ("Warning: K8sClient not initialized, cannot perform TokenReview" )
102- c .Next ()
103- return
104- }
105-
106- // Perform TokenReview on every request (no caching)
107- // Rationale:
108- // - Security: Validates token hasn't been revoked or expired
109- // - Simplicity: Avoids complex cache invalidation logic
110- // - Performance: TokenReview is lightweight (~5-10ms) and runs only in fallback path
111- // (production uses oauth-proxy with X-Forwarded-* headers, bypassing this code)
112- // - Short-lived tokens: ServiceAccount tokens can be rotated frequently
113- // If TokenReview becomes a bottleneck, consider adding TTL-based cache with 1-minute expiry
114- tr := & authnv1.TokenReview {Spec : authnv1.TokenReviewSpec {Token : token }}
115- rv , err := K8sClient .AuthenticationV1 ().TokenReviews ().Create (c .Request .Context (), tr , v1.CreateOptions {})
116- if err != nil {
117- // Log TokenReview API error with context for debugging
118- log .Printf ("TokenReview API call failed (token len=%d): %v" , len (token ), err )
119- } else if ! rv .Status .Authenticated {
120- // Log authentication failure with reason
121- log .Printf ("TokenReview authentication failed: authenticated=false, error=%q, audiences=%v" ,
122- rv .Status .Error , rv .Status .Audiences )
123- } else if rv .Status .Error != "" {
124- // Log authentication error from Kubernetes
125- log .Printf ("TokenReview returned error: %q (authenticated=%v)" , rv .Status .Error , rv .Status .Authenticated )
126- }
127- if err == nil && rv .Status .Authenticated && rv .Status .Error == "" {
128- username := strings .TrimSpace (rv .Status .User .Username )
129- if username != "" {
130- // Parse username: "system:serviceaccount:namespace:sa-name" or regular username
131- if strings .HasPrefix (username , "system:serviceaccount:" ) {
132- // ServiceAccount: extract namespace and SA name
133- parts := strings .Split (username , ":" )
134- if len (parts ) >= 4 {
135- namespace := parts [2 ]
136- saName := parts [3 ]
137- // Use namespace/sa-name as userID for uniqueness
138- c .Set ("userID" , fmt .Sprintf ("%s/%s" , namespace , saName ))
139- c .Set ("userName" , saName )
140- }
141- } else {
142- // Regular user from OAuth/OIDC
143- c .Set ("userID" , username )
144- c .Set ("userName" , username )
145- }
146-
147- // Extract groups if available
148- if len (rv .Status .User .Groups ) > 0 {
149- c .Set ("userGroups" , rv .Status .User .Groups )
150- }
151- }
152- }
153- }
154- }
155- }
156- }
157-
15886 // Also expose access token if present
15987 auth := c .GetHeader ("Authorization" )
16088 if auth != "" {
0 commit comments