package implsession import ( "context" "net/http" "net/url" "time" "github.com/SigNoz/signoz/pkg/errors" "github.com/SigNoz/signoz/pkg/http/binding" "github.com/SigNoz/signoz/pkg/http/render" "github.com/SigNoz/signoz/pkg/modules/session" "github.com/SigNoz/signoz/pkg/types/authtypes" "github.com/SigNoz/signoz/pkg/valuer" ) type handler struct { module session.Module } func NewHandler(module session.Module) session.Handler { return &handler{module: module} } func (handler *handler) GetSessionContext(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) defer cancel() email, err := valuer.NewEmail(req.URL.Query().Get("email")) if err != nil { render.Error(rw, err) return } siteURL, err := url.Parse(req.URL.Query().Get("ref")) if err != nil { render.Error(rw, err) return } sessionContext, err := handler.module.GetSessionContext(ctx, email, siteURL) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, sessionContext) } func (handler *handler) CreateSessionByEmailPassword(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 15*time.Second) defer cancel() body := new(authtypes.PostableEmailPasswordSession) if err := binding.JSON.BindBody(req.Body, body); err != nil { render.Error(rw, err) return } token, err := handler.module.CreatePasswordAuthNSession(ctx, authtypes.AuthNProviderEmailPassword, body.Email, body.Password, body.OrgID) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, authtypes.NewGettableTokenFromToken(token, handler.module.GetRotationInterval(ctx))) } func (handler *handler) CreateSessionByGoogleCallback(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 15*time.Second) defer cancel() values := req.URL.Query() redirectURL, err := handler.module.CreateCallbackAuthNSession(ctx, authtypes.AuthNProviderGoogleAuth, values) if err != nil { http.Redirect(rw, req, handler.getRedirectURLFromErr(err), http.StatusSeeOther) return } http.Redirect(rw, req, redirectURL, http.StatusSeeOther) } func (handler *handler) CreateSessionBySAMLCallback(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 15*time.Second) defer cancel() err := req.ParseForm() if err != nil { render.Error(rw, err) return } redirectURL, err := handler.module.CreateCallbackAuthNSession(ctx, authtypes.AuthNProviderSAML, req.Form) if err != nil { http.Redirect(rw, req, handler.getRedirectURLFromErr(err), http.StatusSeeOther) return } http.Redirect(rw, req, redirectURL, http.StatusSeeOther) } func (handler *handler) CreateSessionByOIDCCallback(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 15*time.Second) defer cancel() values := req.URL.Query() redirectURL, err := handler.module.CreateCallbackAuthNSession(ctx, authtypes.AuthNProviderOIDC, values) if err != nil { http.Redirect(rw, req, handler.getRedirectURLFromErr(err), http.StatusSeeOther) return } http.Redirect(rw, req, redirectURL, http.StatusSeeOther) } func (handler *handler) RotateSession(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) defer cancel() body := new(authtypes.PostableRotateToken) if err := binding.JSON.BindBody(req.Body, body); err != nil { render.Error(rw, err) return } accessToken, err := authtypes.AccessTokenFromContext(ctx) if err != nil { render.Error(rw, err) return } token, err := handler.module.RotateSession(ctx, accessToken, body.RefreshToken) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusOK, authtypes.NewGettableTokenFromToken(token, handler.module.GetRotationInterval(ctx))) } func (handler *handler) DeleteSession(rw http.ResponseWriter, req *http.Request) { ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) defer cancel() accessToken, err := authtypes.AccessTokenFromContext(ctx) if err != nil { render.Error(rw, err) return } err = handler.module.DeleteSession(ctx, accessToken) if err != nil { render.Error(rw, err) return } render.Success(rw, http.StatusNoContent, nil) } func (*handler) getRedirectURLFromErr(err error) string { values := errors.AsURLValues(err) values.Add("callbackauthnerr", "true") return (&url.URL{ // When UI is being served on a prefix, we need to redirect to the login page on the prefix. Path: "/login", RawQuery: values.Encode(), }).String() }