feat(cache): implement hashed API key storage and retrieval
Adds a new hashed key storage mechanism for API keys in the cache. Replaces direct mapping to API keys with composite keys based on organizationId and name. Implements searching of API keys using hash comparisons for improved security. Updates related tests to ensure correct functionality and validate the hashing. Also, adds support for a new dependency `golang.org/x/crypto`.
This commit is contained in:
+2
-3
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"gitlab.com/unboundsoftware/schemas/domain"
|
||||
"gitlab.com/unboundsoftware/schemas/hash"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,8 +48,8 @@ func (m *AuthMiddleware) Handler(next http.Handler) http.Handler {
|
||||
_, _ = w.Write([]byte("Invalid API Key format"))
|
||||
return
|
||||
}
|
||||
hashedKey := hash.String(apiKey)
|
||||
organization := m.cache.OrganizationByAPIKey(hashedKey)
|
||||
// Cache handles hash comparison internally
|
||||
organization := m.cache.OrganizationByAPIKey(apiKey)
|
||||
if organization != nil {
|
||||
ctx = context.WithValue(ctx, OrganizationKey, *organization)
|
||||
}
|
||||
|
||||
+10
-13
@@ -15,7 +15,6 @@ import (
|
||||
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
|
||||
|
||||
"gitlab.com/unboundsoftware/schemas/domain"
|
||||
"gitlab.com/unboundsoftware/schemas/hash"
|
||||
)
|
||||
|
||||
// MockCache is a mock implementation of the Cache interface
|
||||
@@ -45,9 +44,9 @@ func TestAuthMiddleware_Handler_WithValidAPIKey(t *testing.T) {
|
||||
}
|
||||
|
||||
apiKey := "test-api-key-123"
|
||||
hashedKey := hash.String(apiKey)
|
||||
|
||||
mockCache.On("OrganizationByAPIKey", hashedKey).Return(expectedOrg)
|
||||
// Mock expects plaintext key (cache handles hashing internally)
|
||||
mockCache.On("OrganizationByAPIKey", apiKey).Return(expectedOrg)
|
||||
|
||||
// Create a test handler that checks the context
|
||||
var capturedOrg *domain.Organization
|
||||
@@ -84,9 +83,9 @@ func TestAuthMiddleware_Handler_WithInvalidAPIKey(t *testing.T) {
|
||||
authMiddleware := NewAuth(mockCache)
|
||||
|
||||
apiKey := "invalid-api-key"
|
||||
hashedKey := hash.String(apiKey)
|
||||
|
||||
mockCache.On("OrganizationByAPIKey", hashedKey).Return(nil)
|
||||
// Mock expects plaintext key (cache handles hashing internally)
|
||||
mockCache.On("OrganizationByAPIKey", apiKey).Return(nil)
|
||||
|
||||
// Create a test handler that checks the context
|
||||
var capturedOrg *domain.Organization
|
||||
@@ -120,9 +119,8 @@ func TestAuthMiddleware_Handler_WithoutAPIKey(t *testing.T) {
|
||||
mockCache := new(MockCache)
|
||||
authMiddleware := NewAuth(mockCache)
|
||||
|
||||
// The middleware always hashes the API key (even if empty) and calls the cache
|
||||
emptyKeyHash := hash.String("")
|
||||
mockCache.On("OrganizationByAPIKey", emptyKeyHash).Return(nil)
|
||||
// The middleware passes the plaintext API key (cache handles hashing)
|
||||
mockCache.On("OrganizationByAPIKey", "").Return(nil)
|
||||
|
||||
// Create a test handler that checks the context
|
||||
var capturedOrg *domain.Organization
|
||||
@@ -153,9 +151,8 @@ func TestAuthMiddleware_Handler_WithValidJWT(t *testing.T) {
|
||||
mockCache := new(MockCache)
|
||||
authMiddleware := NewAuth(mockCache)
|
||||
|
||||
// The middleware always hashes the API key (even if empty) and calls the cache
|
||||
emptyKeyHash := hash.String("")
|
||||
mockCache.On("OrganizationByAPIKey", emptyKeyHash).Return(nil)
|
||||
// The middleware passes the plaintext API key (cache handles hashing)
|
||||
mockCache.On("OrganizationByAPIKey", "").Return(nil)
|
||||
|
||||
userID := "user-123"
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
@@ -251,13 +248,13 @@ func TestAuthMiddleware_Handler_BothJWTAndAPIKey(t *testing.T) {
|
||||
|
||||
userID := "user-123"
|
||||
apiKey := "test-api-key-123"
|
||||
hashedKey := hash.String(apiKey)
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"sub": userID,
|
||||
})
|
||||
|
||||
mockCache.On("OrganizationByAPIKey", hashedKey).Return(expectedOrg)
|
||||
// Mock expects plaintext key (cache handles hashing internally)
|
||||
mockCache.On("OrganizationByAPIKey", apiKey).Return(expectedOrg)
|
||||
|
||||
// Create a test handler that checks both user and organization in context
|
||||
var capturedUser string
|
||||
|
||||
Reference in New Issue
Block a user