oidc: Add /api/v1/config route for determining whether to display a login button on the UI

This commit is contained in:
TwiN
2022-01-02 18:29:34 -05:00
parent 8838f6f2ad
commit 425c1d3674
15 changed files with 135 additions and 27 deletions

View File

@ -0,0 +1,26 @@
package handler
import (
"fmt"
"net/http"
"github.com/TwiN/gatus/v3/security"
)
// ConfigHandler is a handler that returns information for the front end of the application.
type ConfigHandler struct {
securityConfig *security.Config
}
func (handler ConfigHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
hasOIDC := false
isAuthenticated := false // Default to true if no security config is set
if handler.securityConfig != nil {
hasOIDC = handler.securityConfig.OIDC != nil
isAuthenticated = handler.securityConfig.IsAuthenticated(r)
}
// Return the config
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(fmt.Sprintf(`{"oidc":%v,"authenticated":%v}`, hasOIDC, isAuthenticated)))
}

View File

@ -0,0 +1,34 @@
package handler
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/TwiN/gatus/v3/security"
"github.com/gorilla/mux"
)
func TestConfigHandler_ServeHTTP(t *testing.T) {
securityConfig := &security.Config{
OIDC: &security.OIDCConfig{
IssuerURL: "https://sso.gatus.io/",
RedirectURL: "http://localhost:80/authorization-code/callback",
Scopes: []string{"openid"},
AllowedSubjects: []string{"user1@example.com"},
},
}
handler := ConfigHandler{securityConfig: securityConfig}
// Create a fake router. We're doing this because I need the gate to be initialized.
securityConfig.ApplySecurityMiddleware(mux.NewRouter())
// Test the config handler
request, _ := http.NewRequest("GET", "/api/v1/config", http.NoBody)
responseRecorder := httptest.NewRecorder()
handler.ServeHTTP(responseRecorder, request)
if responseRecorder.Code != http.StatusOK {
t.Error("expected code to be 200, but was", responseRecorder.Code)
}
if responseRecorder.Body.String() != `{"oidc":true,"authenticated":false}` {
t.Error("expected body to be `{\"oidc\":true,\"authenticated\":false}`, but was", responseRecorder.Body.String())
}
}

View File

@ -4,7 +4,11 @@ import "net/http"
func DevelopmentCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8081")
if r.Method == "OPTIONS" {
return
}
next.ServeHTTP(w, r)
})
}

View File

@ -25,6 +25,7 @@ func CreateRouter(staticFolder string, securityConfig *security.Config, uiConfig
securityConfig.ApplySecurityMiddleware(protected)
}
// Endpoints
unprotected.Handle("/v1/config", ConfigHandler{securityConfig: securityConfig}).Methods("GET")
protected.HandleFunc("/v1/endpoints/statuses", EndpointStatuses).Methods("GET") // No GzipHandler for this one, because we cache the content as Gzipped already
protected.HandleFunc("/v1/endpoints/{key}/statuses", GzipHandlerFunc(EndpointStatus)).Methods("GET")
unprotected.HandleFunc("/v1/endpoints/{key}/uptimes/{duration}/badge.svg", UptimeBadge).Methods("GET")