mirror of
				https://github.com/ClusterCockpit/cc-metric-store.git
				synced 2025-10-30 16:45:07 +01:00 
			
		
		
		
	Cache decoded tokens (signature check is expensive)
This commit is contained in:
		
							
								
								
									
										20
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								api.go
									
									
									
									
									
								
							| @@ -14,6 +14,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/golang-jwt/jwt/v4" | 	"github.com/golang-jwt/jwt/v4" | ||||||
| @@ -280,6 +281,9 @@ func handleQuery(rw http.ResponseWriter, r *http.Request) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func authentication(next http.Handler, publicKey ed25519.PublicKey) http.Handler { | func authentication(next http.Handler, publicKey ed25519.PublicKey) http.Handler { | ||||||
|  | 	cacheLock := sync.RWMutex{} | ||||||
|  | 	cache := map[string]*jwt.Token{} | ||||||
|  |  | ||||||
| 	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { | ||||||
| 		authheader := r.Header.Get("Authorization") | 		authheader := r.Header.Get("Authorization") | ||||||
| 		if authheader == "" || !strings.HasPrefix(authheader, "Bearer ") { | 		if authheader == "" || !strings.HasPrefix(authheader, "Bearer ") { | ||||||
| @@ -287,10 +291,20 @@ func authentication(next http.Handler, publicKey ed25519.PublicKey) http.Handler | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		rawtoken := authheader[len("Bearer "):] | ||||||
|  | 		cacheLock.RLock() | ||||||
|  | 		token, ok := cache[rawtoken] | ||||||
|  | 		cacheLock.RUnlock() | ||||||
|  | 		if ok && token.Claims.Valid() == nil { | ||||||
|  | 			next.ServeHTTP(rw, r) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// The actual token is ignored for now. | 		// The actual token is ignored for now. | ||||||
| 		// In case expiration and so on are specified, the Parse function | 		// In case expiration and so on are specified, the Parse function | ||||||
| 		// already returns an error for expired tokens. | 		// already returns an error for expired tokens. | ||||||
| 		_, err := jwt.Parse(authheader[len("Bearer "):], func(t *jwt.Token) (interface{}, error) { | 		var err error | ||||||
|  | 		token, err = jwt.Parse(rawtoken, func(t *jwt.Token) (interface{}, error) { | ||||||
| 			if t.Method != jwt.SigningMethodEdDSA { | 			if t.Method != jwt.SigningMethodEdDSA { | ||||||
| 				return nil, errors.New("only Ed25519/EdDSA supported") | 				return nil, errors.New("only Ed25519/EdDSA supported") | ||||||
| 			} | 			} | ||||||
| @@ -303,6 +317,10 @@ func authentication(next http.Handler, publicKey ed25519.PublicKey) http.Handler | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		cacheLock.Lock() | ||||||
|  | 		cache[rawtoken] = token | ||||||
|  | 		cacheLock.Unlock() | ||||||
|  |  | ||||||
| 		// Let request through... | 		// Let request through... | ||||||
| 		next.ServeHTTP(rw, r) | 		next.ServeHTTP(rw, r) | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user