Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: pass on correct context during verification #4151

Merged
merged 1 commit into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/client-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
72 changes: 36 additions & 36 deletions selfservice/strategy/code/strategy_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@

f.TransientPayload = body.TransientPayload

if err := flow.MethodEnabledAndAllowed(r.Context(), f.GetFlowName(), s.VerificationStrategyID(), string(body.getMethod()), s.deps); err != nil {
if err := flow.MethodEnabledAndAllowed(ctx, f.GetFlowName(), s.VerificationStrategyID(), string(body.getMethod()), s.deps); err != nil {
return s.handleVerificationError(r, f, body, err)
}

Expand All @@ -158,15 +158,15 @@
case flow.StateChooseMethod:
fallthrough
case flow.StateEmailSent:
return s.verificationHandleFormSubmission(w, r, f, body)
return s.verificationHandleFormSubmission(ctx, w, r, f, body)
case flow.StatePassedChallenge:
return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationRetrySuccess())
return s.retryVerificationFlowWithMessage(ctx, w, r, f.Type, text.NewErrorValidationVerificationRetrySuccess())
default:
return s.retryVerificationFlowWithMessage(w, r, f.Type, text.NewErrorValidationVerificationStateFailure())
return s.retryVerificationFlowWithMessage(ctx, w, r, f.Type, text.NewErrorValidationVerificationStateFailure())

Check warning on line 165 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L165

Added line #L165 was not covered by tests
}
}

func (s *Strategy) handleLinkClick(w http.ResponseWriter, r *http.Request, f *verification.Flow, code string) error {
func (s *Strategy) handleLinkClick(ctx context.Context, w http.ResponseWriter, r *http.Request, f *verification.Flow, code string) error {
// Pre-fill the code
if codeField := f.UI.Nodes.Find("code"); codeField != nil {
codeField.Attributes.SetValue(code)
Expand All @@ -178,41 +178,41 @@
f.UI.SetCSRF(csrfToken)
f.CSRFToken = csrfToken

if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return err
}

// we always redirect to the browser UI here to allow API flows to complete aswell
// TODO: In the future, we might want to redirect to a custom URI scheme here, to allow to open an app on the device of
// the user to handle the flow directly.
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther)
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(ctx)).String(), http.StatusSeeOther)

return errors.WithStack(flow.ErrCompletedByStrategy)
}

func (s *Strategy) verificationHandleFormSubmission(w http.ResponseWriter, r *http.Request, f *verification.Flow, body *updateVerificationFlowWithCodeMethod) error {
func (s *Strategy) verificationHandleFormSubmission(ctx context.Context, w http.ResponseWriter, r *http.Request, f *verification.Flow, body *updateVerificationFlowWithCodeMethod) error {
if len(body.Code) > 0 {
if r.Method == http.MethodGet {
// Special case: in the code strategy we send out links as well, that contain the code
return s.handleLinkClick(w, r, f, body.Code)
return s.handleLinkClick(ctx, w, r, f, body.Code)
}

// If not GET: try to use the submitted code
return s.verificationUseCode(w, r, body.Code, f)
return s.verificationUseCode(ctx, w, r, body.Code, f)
} else if len(body.Email) == 0 {
// If no code and no email was provided, fail with a validation error
return s.handleVerificationError(r, f, body, schema.NewRequiredError("#/email", "email"))
}

if err := flow.EnsureCSRF(s.deps, r, f.Type, s.deps.Config().DisableAPIFlowEnforcement(r.Context()), s.deps.GenerateCSRFToken, body.CSRFToken); err != nil {
if err := flow.EnsureCSRF(s.deps, r, f.Type, s.deps.Config().DisableAPIFlowEnforcement(ctx), s.deps.GenerateCSRFToken, body.CSRFToken); err != nil {
return s.handleVerificationError(r, f, body, err)
}

if err := s.deps.VerificationCodePersister().DeleteVerificationCodesOfFlow(r.Context(), f.ID); err != nil {
if err := s.deps.VerificationCodePersister().DeleteVerificationCodesOfFlow(ctx, f.ID); err != nil {
return s.handleVerificationError(r, f, body, err)
}

if err := s.deps.CodeSender().SendVerificationCode(r.Context(), f, identity.VerifiableAddressTypeEmail, body.Email); err != nil {
if err := s.deps.CodeSender().SendVerificationCode(ctx, f, identity.VerifiableAddressTypeEmail, body.Email); err != nil {
if !errors.Is(err, ErrUnknownAddress) {
return s.handleVerificationError(r, f, body, err)
}
Expand All @@ -232,47 +232,47 @@
)
}

if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return s.handleVerificationError(r, f, body, err)
}

return nil
}

func (s *Strategy) verificationUseCode(w http.ResponseWriter, r *http.Request, codeString string, f *verification.Flow) error {
code, err := s.deps.VerificationCodePersister().UseVerificationCode(r.Context(), f.ID, codeString)
func (s *Strategy) verificationUseCode(ctx context.Context, w http.ResponseWriter, r *http.Request, codeString string, f *verification.Flow) error {
code, err := s.deps.VerificationCodePersister().UseVerificationCode(ctx, f.ID, codeString)
if errors.Is(err, ErrCodeNotFound) {
f.UI.Messages.Clear()
f.UI.Messages.Add(text.NewErrorValidationVerificationCodeInvalidOrAlreadyUsed())
if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
return s.retryVerificationFlowWithError(w, r, f.Type, err)
if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, f.Type, err)

Check warning on line 248 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L248

Added line #L248 was not covered by tests
}

if x.IsBrowserRequest(r) {
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther)
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(ctx)).String(), http.StatusSeeOther)
} else {
s.deps.Writer().Write(w, r, f)
}
return errors.WithStack(flow.ErrCompletedByStrategy)
} else if err != nil {
return s.retryVerificationFlowWithError(w, r, f.Type, err)
return s.retryVerificationFlowWithError(ctx, w, r, f.Type, err)
}

address := code.VerifiableAddress
address.Verified = true
verifiedAt := sqlxx.NullTime(time.Now().UTC())
address.VerifiedAt = &verifiedAt
address.Status = identity.VerifiableAddressStatusCompleted
if err := s.deps.PrivilegedIdentityPool().UpdateVerifiableAddress(r.Context(), address); err != nil {
return s.retryVerificationFlowWithError(w, r, f.Type, err)
if err := s.deps.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, address); err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, f.Type, err)

Check warning on line 267 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L267

Added line #L267 was not covered by tests
}

i, err := s.deps.IdentityPool().GetIdentity(r.Context(), code.VerifiableAddress.IdentityID, identity.ExpandDefault)
i, err := s.deps.IdentityPool().GetIdentity(ctx, code.VerifiableAddress.IdentityID, identity.ExpandDefault)
if err != nil {
return s.retryVerificationFlowWithError(w, r, f.Type, err)
return s.retryVerificationFlowWithError(ctx, w, r, f.Type, err)

Check warning on line 272 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L272

Added line #L272 was not covered by tests
}

returnTo := f.ContinueURL(r.Context(), s.deps.Config())
returnTo := f.ContinueURL(ctx, s.deps.Config())

f.UI = &container.Container{
Method: "GET",
Expand All @@ -288,54 +288,54 @@
Append(node.NewAnchorField("continue", returnTo.String(), node.CodeGroup, text.NewInfoNodeLabelContinue()).
WithMetaLabel(text.NewInfoNodeLabelContinue()))

if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
if err := s.deps.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, flow.TypeBrowser, err)

Check warning on line 292 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L292

Added line #L292 was not covered by tests
}

if err := s.deps.VerificationExecutor().PostVerificationHook(w, r, f, i); err != nil {
return s.retryVerificationFlowWithError(w, r, f.Type, err)
return s.retryVerificationFlowWithError(ctx, w, r, f.Type, err)

Check warning on line 296 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L296

Added line #L296 was not covered by tests
}

return nil
}

func (s *Strategy) retryVerificationFlowWithMessage(w http.ResponseWriter, r *http.Request, ft flow.Type, message *text.Message) error {
func (s *Strategy) retryVerificationFlowWithMessage(ctx context.Context, w http.ResponseWriter, r *http.Request, ft flow.Type, message *text.Message) error {
s.deps.
Logger().
WithRequest(r).
WithField("message", message).
Debug("A verification flow is being retried because a validation error occurred.")

f, err := verification.NewFlow(s.deps.Config(),
s.deps.Config().SelfServiceFlowVerificationRequestLifespan(r.Context()), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft)
s.deps.Config().SelfServiceFlowVerificationRequestLifespan(ctx), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft)
if err != nil {
return s.handleVerificationError(r, f, nil, err)
}

f.UI.Messages.Add(message)

if err := s.deps.VerificationFlowPersister().CreateVerificationFlow(r.Context(), f); err != nil {
if err := s.deps.VerificationFlowPersister().CreateVerificationFlow(ctx, f); err != nil {
return s.handleVerificationError(r, f, nil, err)
}

if x.IsJSONRequest(r) {
s.deps.Writer().WriteError(w, r, flow.NewFlowReplacedError(text.NewErrorSystemGeneric("An error occured, please use the new flow.")).WithFlow(f))
} else {
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther)
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(ctx)).String(), http.StatusSeeOther)

Check warning on line 324 in selfservice/strategy/code/strategy_verification.go

View check run for this annotation

Codecov / codecov/patch

selfservice/strategy/code/strategy_verification.go#L324

Added line #L324 was not covered by tests
}

return errors.WithStack(flow.ErrCompletedByStrategy)
}

func (s *Strategy) retryVerificationFlowWithError(w http.ResponseWriter, r *http.Request, ft flow.Type, verErr error) error {
func (s *Strategy) retryVerificationFlowWithError(ctx context.Context, w http.ResponseWriter, r *http.Request, ft flow.Type, verErr error) error {
s.deps.
Logger().
WithRequest(r).
WithError(verErr).
Debug("A verification flow is being retried because an error occurred.")

f, err := verification.NewFlow(s.deps.Config(),
s.deps.Config().SelfServiceFlowVerificationRequestLifespan(r.Context()), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft)
s.deps.Config().SelfServiceFlowVerificationRequestLifespan(ctx), s.deps.CSRFHandler().RegenerateToken(w, r), r, s, ft)
if err != nil {
return s.handleVerificationError(r, f, nil, err)
}
Expand All @@ -349,7 +349,7 @@
return err
}

if err := s.deps.VerificationFlowPersister().CreateVerificationFlow(r.Context(), f); err != nil {
if err := s.deps.VerificationFlowPersister().CreateVerificationFlow(ctx, f); err != nil {
return s.handleVerificationError(r, f, nil, err)
}

Expand All @@ -360,7 +360,7 @@
}
s.deps.Writer().WriteError(w, r, toReturn)
} else {
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(r.Context())).String(), http.StatusSeeOther)
http.Redirect(w, r, f.AppendTo(s.deps.Config().SelfServiceFlowVerificationUI(ctx)).String(), http.StatusSeeOther)
}

return errors.WithStack(flow.ErrCompletedByStrategy)
Expand Down
10 changes: 5 additions & 5 deletions selfservice/strategy/link/strategy_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (s *Strategy) verificationHandleFormSubmission(ctx context.Context, r *http
f.Active = sqlxx.NullString(s.NodeGroup())
f.State = flow.StateEmailSent
f.UI.Messages.Set(text.NewVerificationEmailSent())
if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return s.handleVerificationError(r, f, body, err)
}

Expand All @@ -221,16 +221,16 @@ func (s *Strategy) verificationUseToken(ctx context.Context, w http.ResponseWrit
verifiedAt := sqlxx.NullTime(time.Now().UTC())
address.VerifiedAt = &verifiedAt
address.Status = identity.VerifiableAddressStatusCompleted
if err := s.d.PrivilegedIdentityPool().UpdateVerifiableAddress(r.Context(), address); err != nil {
if err := s.d.PrivilegedIdentityPool().UpdateVerifiableAddress(ctx, address); err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, flow.TypeBrowser, err)
}

i, err := s.d.IdentityPool().GetIdentity(r.Context(), token.VerifiableAddress.IdentityID, identity.ExpandDefault)
i, err := s.d.IdentityPool().GetIdentity(ctx, token.VerifiableAddress.IdentityID, identity.ExpandDefault)
if err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, flow.TypeBrowser, err)
}

returnTo := f.ContinueURL(r.Context(), s.d.Config())
returnTo := f.ContinueURL(ctx, s.d.Config())

f.UI.
Nodes.
Expand All @@ -251,7 +251,7 @@ func (s *Strategy) verificationUseToken(ctx context.Context, w http.ResponseWrit
Append(node.NewAnchorField("continue", returnTo.String(), node.LinkGroup, text.NewInfoNodeLabelContinue()).
WithMetaLabel(text.NewInfoNodeLabelContinue()))

if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(ctx, f); err != nil {
return s.retryVerificationFlowWithError(ctx, w, r, flow.TypeBrowser, err)
}

Expand Down
Loading