fix(login): ensure auth request (#8004)

# Which Problems Are Solved

Potential nil pointers leading to a panic in the login UI.

# How the Problems Are Solved

As of now the login UI did not always check if the authRequest was
actually retrieved form the database, which is ok for some endpoints
which can also be called outside of an auth request.
There are now methods added to ensure the request is loaded.

# Additional Changes

None

# Additional Context

Closes https://github.com/zitadel/DevOps/issues/55
This commit is contained in:
Livio Spring 2024-05-24 16:58:45 +02:00 committed by GitHub
parent 5cfccb1442
commit d058a2bc8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 38 additions and 22 deletions

View File

@ -7,6 +7,7 @@ import (
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/zerrors"
)
const (
@ -23,6 +24,14 @@ func (l *Login) getAuthRequest(r *http.Request) (*domain.AuthRequest, error) {
return l.authRepo.AuthRequestByID(r.Context(), authRequestID, userAgentID)
}
func (l *Login) ensureAuthRequest(r *http.Request) (*domain.AuthRequest, error) {
authRequest, err := l.getAuthRequest(r)
if authRequest != nil || err != nil {
return authRequest, err
}
return nil, zerrors.ThrowInvalidArgument(nil, "LOGIN-OLah9", "invalid or missing auth request")
}
func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*domain.AuthRequest, error) {
authReq, err := l.getAuthRequest(r)
if err != nil {
@ -32,6 +41,15 @@ func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*
return authReq, err
}
func (l *Login) ensureAuthRequestAndParseData(r *http.Request, data interface{}) (*domain.AuthRequest, error) {
authReq, err := l.ensureAuthRequest(r)
if err != nil {
return authReq, err
}
err = l.parser.Parse(r, data)
return authReq, err
}
func (l *Login) getParseData(r *http.Request, data interface{}) error {
return l.parser.Parse(r, data)
}

View File

@ -20,7 +20,7 @@ type changePasswordData struct {
func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) {
data := new(changePasswordData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -14,7 +14,6 @@ import (
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/zerrors"
)
const (
@ -145,9 +144,8 @@ func (l *Login) redirectDeviceAuthStart(w http.ResponseWriter, r *http.Request,
// When the action of "allowed" or "denied", the device authorization is updated accordingly.
// Else the user is presented with a page where they can choose / submit either action.
func (l *Login) handleDeviceAuthAction(w http.ResponseWriter, r *http.Request) {
authReq, err := l.getAuthRequest(r)
if authReq == nil {
err = zerrors.ThrowInvalidArgument(err, "LOGIN-OLah8", "invalid or missing auth request")
authReq, err := l.ensureAuthRequest(r)
if err != nil {
l.redirectDeviceAuthStart(w, r, err.Error())
return
}

View File

@ -127,7 +127,7 @@ func (l *Login) handleExternalLogin(w http.ResponseWriter, r *http.Request) {
// handleExternalRegister is called when a user selects the idp on the register options page
func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
data := new(externalIDPData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return
@ -657,7 +657,7 @@ func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Requ
// and either links or creates an externalUser
func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http.Request) {
data := new(externalNotFoundOptionFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
return

View File

@ -42,7 +42,7 @@ func (l *Login) renderLDAPLogin(w http.ResponseWriter, r *http.Request, authReq
func (l *Login) handleLDAPCallback(w http.ResponseWriter, r *http.Request) {
data := new(ldapFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -44,7 +44,7 @@ func (l *Login) renderLinkingUserPrompt(w http.ResponseWriter, r *http.Request,
func (l *Login) handleLinkingUserPrompt(w http.ResponseWriter, r *http.Request) {
data := new(linkingUserPromptFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderLogin(w, r, authReq, err)
return

View File

@ -71,7 +71,7 @@ func (l *Login) renderRegisterSMS(w http.ResponseWriter, r *http.Request, authRe
// and a successful OTP SMS check will be added to the auth request.
func (l *Login) handleRegisterSMSCheck(w http.ResponseWriter, r *http.Request) {
formData := new(smsInitFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
authReq, err := l.ensureAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -42,7 +42,7 @@ func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authRe
func (l *Login) handleRegisterU2F(w http.ResponseWriter, r *http.Request) {
data := new(webAuthNFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -26,7 +26,7 @@ type mfaInitVerifyData struct {
func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) {
data := new(mfaInitVerifyData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -18,7 +18,7 @@ type mfaPromptData struct {
func (l *Login) handleMFAPrompt(w http.ResponseWriter, r *http.Request) {
data := new(mfaPromptData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -19,7 +19,7 @@ type mfaVerifyFormData struct {
func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) {
data := new(mfaVerifyFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -75,8 +75,8 @@ func (l *Login) renderOTPVerification(w http.ResponseWriter, r *http.Request, au
// A user is also able to request a code resend or choose another provider.
func (l *Login) handleOTPVerificationCheck(w http.ResponseWriter, r *http.Request) {
formData := new(mfaOTPFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
if authReq == nil || err != nil {
authReq, err := l.ensureAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return
}

View File

@ -50,7 +50,7 @@ func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, au
func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) {
formData := new(mfaU2FFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
authReq, err := l.ensureAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -34,7 +34,7 @@ func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *
func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) {
data := new(passwordFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -12,7 +12,7 @@ const (
)
func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) {
authReq, err := l.getAuthRequest(r)
authReq, err := l.ensureAuthRequest(r)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -49,7 +49,7 @@ func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Re
func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Request) {
formData := new(passwordlessFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
authReq, err := l.ensureAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return

View File

@ -36,7 +36,7 @@ func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, auth
func (l *Login) handleSelectUser(w http.ResponseWriter, r *http.Request) {
data := new(userSelectionFormData)
authSession, err := l.getAuthRequestAndParseData(r, data)
authSession, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authSession, err)
return

View File

@ -27,7 +27,7 @@ func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, aut
func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
data := new(changeUsernameData)
authReq, err := l.getAuthRequestAndParseData(r, data)
authReq, err := l.ensureAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return