Files
wonderwall/pkg/router/router.go
2023-11-28 10:12:15 +01:00

124 lines
3.8 KiB
Go

package router
import (
"net/http"
"github.com/riandyrn/otelchi"
"github.com/go-chi/chi/v5"
chi_middleware "github.com/go-chi/chi/v5/middleware"
"github.com/nais/wonderwall/pkg/config"
"github.com/nais/wonderwall/pkg/ingress"
"github.com/nais/wonderwall/pkg/middleware"
"github.com/nais/wonderwall/pkg/router/paths"
)
var noopHandler = func(w http.ResponseWriter, r *http.Request) {}
type Source interface {
Handlers
Config
}
type Handlers interface {
// Login initiates the authorization code flow.
Login(http.ResponseWriter, *http.Request)
// LoginCallback handles the authentication response from the identity provider.
LoginCallback(http.ResponseWriter, *http.Request)
// Logout triggers self-initiated logout for the current user, as well as single-logout at the identity provider.
Logout(http.ResponseWriter, *http.Request)
// LogoutCallback handles the callback initiated by the self-initiated logout after single-logout at the identity provider.
LogoutCallback(http.ResponseWriter, *http.Request)
// LogoutFrontChannel performs a local logout initiated by a third party in the SSO circle-of-trust.
LogoutFrontChannel(http.ResponseWriter, *http.Request)
// LogoutLocal clears the current user's local session for logout, without triggering single-logout at the identity provider.
LogoutLocal(http.ResponseWriter, *http.Request)
// Session returns metadata for the current user's session.
Session(http.ResponseWriter, *http.Request)
// SessionRefresh refreshes current user's session and returns the associated updated metadata.
SessionRefresh(http.ResponseWriter, *http.Request)
// Wildcard handles all requests not matching the other handlers.
Wildcard(http.ResponseWriter, *http.Request)
}
type Config interface {
GetIngresses() *ingress.Ingresses
}
func New(src Source, cfg *config.Config) chi.Router {
providerName := string(cfg.OpenID.Provider)
ingressMw := middleware.Ingress(src)
prometheus := middleware.Prometheus(providerName)
logentry := middleware.LogEntry(providerName)
r := chi.NewRouter()
r.Use(middleware.CorrelationIDHandler)
r.Use(chi_middleware.Recoverer)
r.Use(ingressMw.Handler)
if cfg.OpenTelemetry.Enabled {
r.Use(otelchi.Middleware(cfg.OpenTelemetry.ServiceName,
otelchi.WithChiRoutes(r),
otelchi.WithRequestMethodInSpanName(true)))
}
prefixes := src.GetIngresses().Paths()
cors := func(allowedMethods ...string) func(http.Handler) http.Handler {
return middleware.Cors(cfg, allowedMethods)
}
r.Group(func(r chi.Router) {
r.Use(logentry.Handler)
r.Use(prometheus.Handler)
r.Use(chi_middleware.NoCache)
for _, prefix := range prefixes {
r.Route(prefix+paths.OAuth2, func(r chi.Router) {
r.Get(paths.Login, src.Login)
r.Head(paths.Login, src.Login)
r.Get(paths.Logout, src.Logout)
r.Head(paths.Logout, src.Logout)
r.Get(paths.LoginCallback, src.LoginCallback)
r.Get(paths.LogoutCallback, src.LogoutCallback)
r.Get(paths.LogoutFrontChannel, src.LogoutFrontChannel)
if cfg.OpenID.Provider != config.ProviderIDPorten {
r.Get(paths.LogoutLocal, src.LogoutLocal)
r.Head(paths.LogoutLocal, src.LogoutLocal)
}
r.Get(paths.Ping, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("pong"))
})
r.Route(paths.Session, func(r chi.Router) {
if cfg.SSO.Enabled {
r.Use(cors(http.MethodGet, http.MethodPost))
r.Options("/", noopHandler)
r.Options(paths.Refresh, noopHandler)
}
r.Get("/", src.Session)
r.Get(paths.Refresh, src.SessionRefresh)
r.Post(paths.Refresh, src.SessionRefresh)
})
})
}
if cfg.SSO.IsServer() {
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, paths.OAuth2+paths.Login, http.StatusFound)
})
}
})
r.HandleFunc("/*", src.Wildcard)
return r
}