mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-09 17:53:41 +00:00
fix(idp): correctly get data from cache before parsing (#9134)
# Which Problems Are Solved IdPs using form callback were not always correctly handled with the newly introduced cache mechanism (https://github.com/zitadel/zitadel/pull/9097). # How the Problems Are Solved Get the data from cache before parsing it. # Additional Changes None # Additional Context Relates to https://github.com/zitadel/zitadel/pull/9097
This commit is contained in:
parent
fa5e590aab
commit
8d7a1efd4a
@ -3,6 +3,7 @@ package login
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/crewjam/saml/samlsp"
|
"github.com/crewjam/saml/samlsp"
|
||||||
@ -36,6 +37,9 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
queryIDPConfigID = "idpConfigID"
|
queryIDPConfigID = "idpConfigID"
|
||||||
|
queryState = "state"
|
||||||
|
queryRelayState = "RelayState"
|
||||||
|
queryMethod = "method"
|
||||||
tmplExternalNotFoundOption = "externalnotfoundoption"
|
tmplExternalNotFoundOption = "externalnotfoundoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -214,9 +218,9 @@ func (l *Login) handleExternalLoginCallbackForm(w http.ResponseWriter, r *http.R
|
|||||||
l.renderLogin(w, r, nil, err)
|
l.renderLogin(w, r, nil, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state := r.Form.Get("state")
|
state := r.Form.Get(queryState)
|
||||||
if state == "" {
|
if state == "" {
|
||||||
state = r.Form.Get("RelayState")
|
state = r.Form.Get(queryRelayState)
|
||||||
}
|
}
|
||||||
if state == "" {
|
if state == "" {
|
||||||
l.renderLogin(w, r, nil, zerrors.ThrowInvalidArgument(nil, "LOGIN-dsg3f", "Errors.AuthRequest.NotFound"))
|
l.renderLogin(w, r, nil, zerrors.ThrowInvalidArgument(nil, "LOGIN-dsg3f", "Errors.AuthRequest.NotFound"))
|
||||||
@ -227,12 +231,23 @@ func (l *Login) handleExternalLoginCallbackForm(w http.ResponseWriter, r *http.R
|
|||||||
State: state,
|
State: state,
|
||||||
Form: r.Form,
|
Form: r.Form,
|
||||||
})
|
})
|
||||||
http.Redirect(w, r, HandlerPrefix+EndpointExternalLoginCallback+"?method=POST&state="+state, 302)
|
v := url.Values{}
|
||||||
|
v.Set(queryMethod, http.MethodPost)
|
||||||
|
v.Set(queryState, state)
|
||||||
|
http.Redirect(w, r, HandlerPrefix+EndpointExternalLoginCallback+"?"+v.Encode(), 302)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleExternalLoginCallback handles the callback from a IDP
|
// handleExternalLoginCallback handles the callback from a IDP
|
||||||
// and tries to extract the user with the provided data
|
// and tries to extract the user with the provided data
|
||||||
func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Request) {
|
func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// workaround because of CSRF on external identity provider flows using form_post
|
||||||
|
if r.URL.Query().Get(queryMethod) == http.MethodPost {
|
||||||
|
if err := l.setDataFromFormCallback(r, r.URL.Query().Get(queryState)); err != nil {
|
||||||
|
l.renderLogin(w, r, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data := new(externalIDPCallbackData)
|
data := new(externalIDPCallbackData)
|
||||||
err := l.getParseData(r, data)
|
err := l.getParseData(r, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -242,10 +257,6 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
|||||||
if data.State == "" {
|
if data.State == "" {
|
||||||
data.State = data.RelayState
|
data.State = data.RelayState
|
||||||
}
|
}
|
||||||
// workaround because of CSRF on external identity provider flows
|
|
||||||
if data.Method == http.MethodPost {
|
|
||||||
l.setDataFromFormCallback(r, data.State)
|
|
||||||
}
|
|
||||||
|
|
||||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||||
authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID)
|
authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID)
|
||||||
@ -356,15 +367,23 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
|||||||
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) setDataFromFormCallback(r *http.Request, state string) {
|
func (l *Login) setDataFromFormCallback(r *http.Request, state string) error {
|
||||||
r.Method = http.MethodPost
|
r.Method = http.MethodPost
|
||||||
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// fallback to the form data in case the request was started before the cache was implemented
|
// fallback to the form data in case the request was started before the cache was implemented
|
||||||
r.PostForm = r.Form
|
r.PostForm = r.Form
|
||||||
idpCallback, ok := l.caches.idpFormCallbacks.Get(r.Context(), idpFormCallbackIndexRequestID,
|
idpCallback, ok := l.caches.idpFormCallbacks.Get(r.Context(), idpFormCallbackIndexRequestID,
|
||||||
idpFormCallbackKey(authz.GetInstance(r.Context()).InstanceID(), state))
|
idpFormCallbackKey(authz.GetInstance(r.Context()).InstanceID(), state))
|
||||||
if ok {
|
if ok {
|
||||||
r.PostForm = idpCallback.Form
|
r.PostForm = idpCallback.Form
|
||||||
|
// We need to set the form as well to make sure the data is parsed correctly.
|
||||||
|
// Form precedes PostForm in the parsing order.
|
||||||
|
r.Form = idpCallback.Form
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) tryMigrateExternalUserID(r *http.Request, session idp.Session, authReq *domain.AuthRequest, externalUser *domain.ExternalUser) (previousIDMatched bool, err error) {
|
func (l *Login) tryMigrateExternalUserID(r *http.Request, session idp.Session, authReq *domain.AuthRequest, externalUser *domain.ExternalUser) (previousIDMatched bool, err error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user