package authdaemon import ( "encoding/json" "net/http" "github.com/fosrl/newt/logger" ) // registerRoutes registers all API routes. Add new endpoints here. func (s *Server) registerRoutes() { s.mux.HandleFunc("/health", s.handleHealth) s.mux.HandleFunc("/connection", s.handleConnection) } // ConnectionMetadata is the metadata object in POST /connection. type ConnectionMetadata struct { Sudo bool `json:"sudo"` Homedir bool `json:"homedir"` } // ConnectionRequest is the JSON body for POST /connection. type ConnectionRequest struct { CaCert string `json:"caCert"` NiceId string `json:"niceId"` Username string `json:"username"` Metadata ConnectionMetadata `json:"metadata"` } // healthResponse is the JSON body for GET /health. type healthResponse struct { Status string `json:"status"` } // handleHealth responds with 200 and {"status":"ok"}. func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) return } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(healthResponse{Status: "ok"}) } // ProcessConnection runs the same logic as POST /connection: CA cert, sshd config, user create/reconcile, principals. // Use this when DisableHTTPS is true (e.g. embedded in Newt) instead of calling the API. func (s *Server) ProcessConnection(req ConnectionRequest) { logger.Info("connection: niceId=%q username=%q metadata.sudo=%v metadata.homedir=%v", req.NiceId, req.Username, req.Metadata.Sudo, req.Metadata.Homedir) cfg := &s.cfg if cfg.CACertPath != "" { if err := writeCACertIfNotExists(cfg.CACertPath, req.CaCert); err != nil { logger.Warn("auth-daemon: write CA cert: %v", err) } sshdConfig := cfg.SSHDConfigPath if sshdConfig == "" { sshdConfig = "/etc/ssh/sshd_config" } if err := ensureSSHDTrustedUserCAKeys(sshdConfig, cfg.CACertPath); err != nil { logger.Warn("auth-daemon: sshd_config: %v", err) } if cfg.ReloadSSHCommand != "" { if err := reloadSSHD(cfg.ReloadSSHCommand); err != nil { logger.Warn("auth-daemon: reload sshd: %v", err) } } } if err := ensureUser(req.Username, req.Metadata); err != nil { logger.Warn("auth-daemon: ensure user: %v", err) } if cfg.PrincipalsFilePath != "" { if err := writePrincipals(cfg.PrincipalsFilePath, req.Username, req.NiceId); err != nil { logger.Warn("auth-daemon: write principals: %v", err) } } } // handleConnection accepts POST with connection payload and delegates to ProcessConnection. func (s *Server) handleConnection(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) return } var req ConnectionRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } s.ProcessConnection(req) w.WriteHeader(http.StatusOK) }