Rename redirect-path to continue + handle redirection on forbidden from wrong org assume

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-02-11 21:19:15 +04:00
parent 942b6f5144
commit e46c1d4894
15 changed files with 74 additions and 55 deletions

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"github.com/go-chi/chi/v5"
"go.gearno.de/kit/httpserver"
@@ -11,6 +12,7 @@ import (
"go.probo.inc/probo/pkg/baseurl"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/saferedirect"
"go.probo.inc/probo/pkg/securecookie"
"go.probo.inc/probo/pkg/server/api/authn"
)
@@ -20,6 +22,7 @@ type SAMLHandler struct {
sessionCookie *authn.Cookie
baseURL *baseurl.BaseURL
logger *log.Logger
safeRedirect *saferedirect.SafeRedirect
}
func NewSAMLHandler(iam *iam.Service, cookieConfig securecookie.Config, baseURL *baseurl.BaseURL, logger *log.Logger) *SAMLHandler {
@@ -28,10 +31,11 @@ func NewSAMLHandler(iam *iam.Service, cookieConfig securecookie.Config, baseURL
sessionCookie: authn.NewCookie(&cookieConfig),
baseURL: baseURL,
logger: logger,
safeRedirect: &saferedirect.SafeRedirect{AllowedHost: baseURL.Host()},
}
}
func (h *SAMLHandler) renderInternalServerError(w http.ResponseWriter, r *http.Request) {
func (h *SAMLHandler) renderInternalServerError(w http.ResponseWriter) {
httpserver.RenderError(w, http.StatusInternalServerError, errors.New("internal server error"))
}
@@ -63,7 +67,7 @@ func (h *SAMLHandler) ConsumeHandler(w http.ResponseWriter, r *http.Request) {
return
}
configIDStr := relayState[:gid.EncodedGIDSize+1]
configIDStr := relayState[:gid.EncodedGIDSize]
if configIDStr == "" {
httpserver.RenderError(w, http.StatusBadRequest, errors.New("missing config ID"))
return
@@ -75,16 +79,21 @@ func (h *SAMLHandler) ConsumeHandler(w http.ResponseWriter, r *http.Request) {
return
}
redirectPath := relayState[gid.EncodedGIDSize+1:]
user, membership, err := h.iam.SAMLService.HandleAssertion(ctx, samlResponse, configID)
if err != nil {
httpserver.RenderError(w, http.StatusUnauthorized, err)
return
}
if redirectPath == "" {
redirectPath = "/organizations/" + membership.OrganizationID.String()
continueURL := "/organizations/" + membership.OrganizationID.String()
if len(relayState) > gid.EncodedGIDSize {
unescapedContinueURL, err := url.QueryUnescape(relayState[gid.EncodedGIDSize:])
if err != nil {
h.logger.WarnCtx(ctx, "cannot unescape continue URL from RelayState", log.Error(err))
} else {
continueURL = unescapedContinueURL
}
}
rootSession := authn.SessionFromContext(ctx)
@@ -94,21 +103,21 @@ func (h *SAMLHandler) ConsumeHandler(w http.ResponseWriter, r *http.Request) {
rootSession, err = h.iam.AuthService.OpenSessionWithSAML(ctx, user.ID)
if err != nil {
h.logger.ErrorCtx(ctx, "cannot open root session", log.Error(err))
h.renderInternalServerError(w, r)
h.renderInternalServerError(w)
return
}
case rootSession.IdentityID != user.ID:
err = h.iam.SessionService.CloseSession(ctx, rootSession.ID)
if err != nil {
h.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
h.renderInternalServerError(w, r)
h.renderInternalServerError(w)
return
}
rootSession, err = h.iam.AuthService.OpenSessionWithSAML(ctx, user.ID)
if err != nil {
h.logger.ErrorCtx(ctx, "cannot open root session", log.Error(err))
h.renderInternalServerError(w, r)
h.renderInternalServerError(w)
return
}
}
@@ -116,14 +125,13 @@ func (h *SAMLHandler) ConsumeHandler(w http.ResponseWriter, r *http.Request) {
_, _, err = h.iam.SessionService.OpenSAMLChildSessionForOrganization(ctx, rootSession.ID, membership.OrganizationID)
if err != nil {
h.logger.ErrorCtx(ctx, "cannot open SAML child session", log.Error(err))
h.renderInternalServerError(w, r)
h.renderInternalServerError(w)
return
}
h.sessionCookie.Set(w, rootSession)
redirectURL := h.baseURL.WithPath(redirectPath).MustString()
http.Redirect(w, r, redirectURL, http.StatusFound)
h.safeRedirect.Redirect(w, r, continueURL, "/organizations/"+membership.OrganizationID.String(), http.StatusFound)
}
func (h *SAMLHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
@@ -135,7 +143,7 @@ func (h *SAMLHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
return
}
redirectPathQueryParam := r.URL.Query().Get("redirect-path")
continueURLQueryParam := r.URL.Query().Get("continue")
samlConfigID, err := gid.ParseGID(samlConfigIDParam)
if err != nil {
@@ -143,7 +151,7 @@ func (h *SAMLHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
return
}
url, err := h.iam.SAMLService.InitiateLogin(ctx, samlConfigID, redirectPathQueryParam)
url, err := h.iam.SAMLService.InitiateLogin(ctx, samlConfigID, continueURLQueryParam)
if err != nil {
panic(fmt.Errorf("cannot initiate SAML login: %w", err))
}