package httpapi import ( "net/http" "net/url" "strings" ) type authConfigResp struct { AuthMode string `json:"auth_mode"` BrokerURL string `json:"broker_url"` BrokerApp string `json:"broker_app"` } // handleAuthConfig publishes the Auth Broker coordinates native clients (the desktop) // need to run the broker device-authorization flow: the broker's public URL + this // app's key in the broker apps registry. Public (it bootstraps native login). func (s *Server) handleAuthConfig(w http.ResponseWriter, _ *http.Request) { writeJSON(w, http.StatusOK, authConfigResp{ AuthMode: s.cfg.AuthMode, BrokerURL: s.cfg.BrokerPublicURL, BrokerApp: s.cfg.BrokerAppOrDefault(), }) } // handleAuthLogin 302-redirects the browser to the Auth Broker's public login page // for global SSO (the broker handles Casdoor and sets its domain cookie; on return the // edge injects X-Auth from that cookie). cdrop owns this redirect so the broker's // public URL lives in one server-side config. Public (it bootstraps login). The rd // (return target) is constrained to this deployment's own origin — an open-redirect // guard — defaulting to the site root. func (s *Server) handleAuthLogin(w http.ResponseWriter, r *http.Request) { if s.cfg.BrokerPublicURL == "" { writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "login redirect not configured"}) return } rd := s.safeReturnTarget(r.URL.Query().Get("rd")) dest := strings.TrimRight(s.cfg.BrokerPublicURL, "/") + "/login?rd=" + url.QueryEscape(rd) http.Redirect(w, r, dest, http.StatusFound) } // safeReturnTarget validates a post-login return URL against this deployment's origin, // falling back to the site root. It blocks open redirects: only a same-origin absolute // URL (or, when no site origin is configured in dev, a site-relative path) is accepted. func (s *Server) safeReturnTarget(rd string) string { if s.siteOrigin == "" { // dev: accept only a site-relative path, never an absolute URL. if strings.HasPrefix(rd, "/") && !strings.HasPrefix(rd, "//") { return rd } return "/" } if u, err := url.Parse(rd); err == nil && u.Scheme != "" && u.Host != "" { if u.Scheme+"://"+u.Host == s.siteOrigin { return rd } } return s.siteOrigin + "/" }