security: Terminal-Endpoint JWT-only (kein API-Key Zugriff)
- Neue JWTOnlyAuth Middleware: akzeptiert nur JWT, kein API-Key - Terminal-Route aus allgemeinem CombinedAuth raus, eigener Mount - API-Keys für Monitoring/Automation erlaubt, aber Terminal braucht echten Login mit User/Pass + 2FA - ?token= Query-Param weiterhin erlaubt (Browser-WS kann kein Header setzen)
This commit is contained in:
parent
e9a47bee26
commit
91385b42d1
@ -136,6 +136,38 @@ func CombinedAuth(validKeys []string, auth *AuthHandler, next http.Handler) http
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JWTOnlyAuth - Nur JWT akzeptieren, kein API-Key (z.B. fuer Terminal-Zugriff)
|
||||||
|
// Erfordert echten Login mit User/Pass (+2FA), kein Maschinentoken reicht.
|
||||||
|
func JWTOnlyAuth(auth *AuthHandler, next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var jwtToken string
|
||||||
|
|
||||||
|
// Authorization Header
|
||||||
|
authHeader := r.Header.Get("Authorization")
|
||||||
|
if strings.HasPrefix(authHeader, "Bearer ") {
|
||||||
|
jwtToken = strings.TrimPrefix(authHeader, "Bearer ")
|
||||||
|
}
|
||||||
|
// ?token= Query-Parameter (fuer WebSocket, Browser kann keinen Header setzen)
|
||||||
|
if jwtToken == "" {
|
||||||
|
jwtToken = r.URL.Query().Get("token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if jwtToken == "" {
|
||||||
|
http.Error(w, `{"error":"unauthorized: JWT erforderlich"}`, http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := auth.ValidateToken(jwtToken)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, `{"error":"unauthorized: ungültiger Token"}`, http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.WithValue(r.Context(), UserContextKey, claims)
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// CORS Middleware
|
// CORS Middleware
|
||||||
func CORS(next http.Handler) http.Handler {
|
func CORS(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@ -17,8 +17,8 @@ var termUpgrader = websocket.Upgrader{
|
|||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
}
|
}
|
||||||
|
|
||||||
// terminalHandler bridget Browser-WebSocket mit Agent-PTY
|
// TerminalHandler bridget Browser-WebSocket mit Agent-PTY (JWT-only, kein API-Key)
|
||||||
func (h *Handler) terminalHandler(hub *ws.Hub) http.HandlerFunc {
|
func (h *Handler) TerminalHandler(hub *ws.Hub) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
agentID := r.PathValue("id")
|
agentID := r.PathValue("id")
|
||||||
if agentID == "" {
|
if agentID == "" {
|
||||||
|
|||||||
@ -45,7 +45,7 @@ func (h *Handler) setupTunnelRoutes(mux *http.ServeMux, hub *ws.Hub) {
|
|||||||
mux.HandleFunc("GET /api/v1/agents/{id}/backups/diff", h.diffBackups())
|
mux.HandleFunc("GET /api/v1/agents/{id}/backups/diff", h.diffBackups())
|
||||||
|
|
||||||
// Terminal-Endpoint (Browser -> Agent PTY)
|
// Terminal-Endpoint (Browser -> Agent PTY)
|
||||||
mux.HandleFunc("GET /api/v1/agents/{id}/terminal", h.terminalHandler(hub))
|
// Terminal wird NICHT hier registriert — wird in main.go unter JWTOnlyAuth eingebunden
|
||||||
|
|
||||||
// WebSocket-Endpoint
|
// WebSocket-Endpoint
|
||||||
mux.HandleFunc("GET /api/v1/agent/ws", ws.NewWebSocketHandler(hub))
|
mux.HandleFunc("GET /api/v1/agent/ws", ws.NewWebSocketHandler(hub))
|
||||||
|
|||||||
@ -93,6 +93,12 @@ func main() {
|
|||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("POST /api/v1/auth/login", authMux)
|
mux.Handle("POST /api/v1/auth/login", authMux)
|
||||||
mux.Handle("POST /api/v1/auth/2fa/validate", authMux) // 2FA-Schritt 2 ebenfalls ohne JWT
|
mux.Handle("POST /api/v1/auth/2fa/validate", authMux) // 2FA-Schritt 2 ebenfalls ohne JWT
|
||||||
|
|
||||||
|
// Terminal: JWT-only (kein API-Key reicht — erfordert echten Login mit 2FA)
|
||||||
|
terminalMux := http.NewServeMux()
|
||||||
|
terminalMux.HandleFunc("GET /api/v1/agents/{id}/terminal", handler.TerminalHandler(hub))
|
||||||
|
mux.Handle("GET /api/v1/agents/{id}/terminal", api.JWTOnlyAuth(authHandler, terminalMux))
|
||||||
|
|
||||||
mux.Handle("/", api.CombinedAuthWithCache(apiKeyCache, authHandler, protectedMux))
|
mux.Handle("/", api.CombinedAuthWithCache(apiKeyCache, authHandler, protectedMux))
|
||||||
|
|
||||||
// Middleware-Chain: CORS -> Logging -> Handler
|
// Middleware-Chain: CORS -> Logging -> Handler
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user