Skip to content

Commit

Permalink
api keys between web and cloud api starting to work
Browse files Browse the repository at this point in the history
  • Loading branch information
mfreeman451 committed Feb 26, 2025
1 parent 7e90364 commit ec006c7
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 25 deletions.
1 change: 1 addition & 0 deletions cmd/cloud/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func run() error {
apiServer := api.NewAPIServer(
api.WithMetricsManager(server.GetMetricsManager()),
api.WithSNMPManager(server.GetSNMPManager()),
api.WithAPIKey(cfg.APIKey), // Pass the API key from config
)

server.SetAPIServer(apiServer)
Expand Down
14 changes: 11 additions & 3 deletions pkg/cloud/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ func NewAPIServer(options ...func(server *APIServer)) *APIServer {
s := &APIServer{
nodes: make(map[string]*NodeStatus),
router: mux.NewRouter(),
apiKey: "", // Default empty API key
}

for _, o := range options {
o(s)
}

s.setupRoutes()
s.setupRoutes(s.apiKey)

return s
}
Expand All @@ -42,16 +43,23 @@ func WithSNMPManager(m snmp.SNMPManager) func(server *APIServer) {
}
}

func WithAPIKey(apiKey string) func(server *APIServer) {
return func(server *APIServer) {
server.apiKey = apiKey
}
}

func WithDB(db db.Service) func(server *APIServer) {
return func(server *APIServer) {
server.db = db
}
}
func (s *APIServer) setupRoutes() {

func (s *APIServer) setupRoutes(apiKey string) {
// Create a middleware chain
middlewareChain := func(next http.Handler) http.Handler {
// Order matters: first API key check, then CORS headers
return srHttp.CommonMiddleware(srHttp.APIKeyMiddleware(next))
return srHttp.CommonMiddleware(srHttp.APIKeyMiddleware(apiKey)(next))
}

// Add middleware to router
Expand Down
1 change: 1 addition & 0 deletions pkg/cloud/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@ type APIServer struct {
snmpManager snmp.SNMPManager
db db.Service
knownPollers []string
apiKey string
}
1 change: 1 addition & 0 deletions pkg/cloud/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Config struct {
Metrics Metrics `json:"metrics"`
SNMP snmp.Config `json:"snmp"`
Security *models.SecurityConfig `json:"security"`
APIKey string `json:"api_key,omitempty"`
}

type Server struct {
Expand Down
53 changes: 31 additions & 22 deletions pkg/http/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,43 @@ func CommonMiddleware(next http.Handler) http.Handler {
}

// APIKeyMiddleware creates middleware that validates API keys.
func APIKeyMiddleware(next http.Handler) http.Handler {
apiKey := os.Getenv("API_KEY")
// It can accept an API key directly or read from the environment.
func APIKeyMiddleware(apiKeyParam string) func(next http.Handler) http.Handler {
apiKey := apiKeyParam

// Fall back to environment variable if not provided directly
if apiKey == "" {
log.Printf("WARNING: API_KEY environment variable not set, API endpoints are unprotected!")
apiKey = os.Getenv("API_KEY")
}

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Skip API key check if it's not configured (development mode)
if apiKey == "" {
next.ServeHTTP(w, r)
if apiKey == "" {
log.Printf("WARNING: API_KEY not set, API endpoints are unprotected!")
}

return
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Skip API key check if it's not configured (development mode)
if apiKey == "" {
next.ServeHTTP(w, r)

// Check API key in header or query parameter
requestKey := r.Header.Get("X-API-Key")
if requestKey == "" {
requestKey = r.URL.Query().Get("api_key")
}
return
}

// Validate API key
if requestKey == "" || requestKey != apiKey {
log.Printf("Unauthorized API access attempt: %s %s", r.Method, r.URL.Path)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
// Check API key in header or query parameter
requestKey := r.Header.Get("X-API-Key")
if requestKey == "" {
requestKey = r.URL.Query().Get("api_key")
}

return
}
// Validate API key
if requestKey == "" || requestKey != apiKey {
log.Printf("Unauthorized API access attempt: %s %s", r.Method, r.URL.Path)
http.Error(w, "Unauthorized", http.StatusUnauthorized)

next.ServeHTTP(w, r)
})
return
}

next.ServeHTTP(w, r)
})
}
}
28 changes: 28 additions & 0 deletions serviceradar-next/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
const url = request.nextUrl.clone();

// Only apply to /api/* paths
if (url.pathname.startsWith('/api/')) {

const apiKey = process.env.API_KEY || '';

// Create a new request with added headers
const modifiedRequest = new Request(url, {
headers: {
...request.headers,
'X-API-Key': apiKey,
},
});

return NextResponse.rewrite(url, { request: modifiedRequest });
}

return NextResponse.next();
}

export const config = {
matcher: '/api/:path*', // Apply middleware only to /api/* routes
};

0 comments on commit ec006c7

Please sign in to comment.