Skip to content

Commit

Permalink
feat: emit admin recovery code event (#4230)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr authored Nov 29, 2024
1 parent f7ddaae commit a7cdc3a
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 34 deletions.
7 changes: 6 additions & 1 deletion selfservice/strategy/code/strategy_recovery_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"time"

"github.com/gobuffalo/pop/v6"

"github.com/gofrs/uuid"
"github.com/julienschmidt/httprouter"
"github.com/pkg/errors"
"go.opentelemetry.io/otel/trace"

"github.com/ory/herodot"
"github.com/ory/kratos/identity"
Expand All @@ -23,6 +23,7 @@ import (
"github.com/ory/kratos/text"
"github.com/ory/kratos/ui/node"
"github.com/ory/kratos/x"
"github.com/ory/kratos/x/events"
"github.com/ory/x/decoderx"
"github.com/ory/x/sqlcon"
"github.com/ory/x/urlx"
Expand Down Expand Up @@ -223,6 +224,10 @@ func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http.
return
}

trace.SpanFromContext(r.Context()).AddEvent(
events.NewRecoveryInitiatedByAdmin(ctx, recoveryFlow.ID, id.ID, flowType.String(), "code"),
)

s.deps.Audit().
WithField("identity_id", id.ID).
WithSensitiveField("recovery_code", rawCode).
Expand Down
28 changes: 17 additions & 11 deletions selfservice/strategy/link/strategy_recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,13 @@ import (
"time"

"github.com/gobuffalo/pop/v6"

"github.com/gofrs/uuid"
"github.com/julienschmidt/httprouter"
"github.com/pkg/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

"github.com/ory/herodot"
"github.com/ory/x/decoderx"
"github.com/ory/x/otelx"
"github.com/ory/x/sqlcon"
"github.com/ory/x/sqlxx"
"github.com/ory/x/urlx"

"github.com/ory/kratos/identity"
"github.com/ory/kratos/schema"
"github.com/ory/kratos/selfservice/flow"
Expand All @@ -33,6 +27,12 @@ import (
"github.com/ory/kratos/text"
"github.com/ory/kratos/ui/node"
"github.com/ory/kratos/x"
"github.com/ory/kratos/x/events"
"github.com/ory/x/decoderx"
"github.com/ory/x/otelx"
"github.com/ory/x/sqlcon"
"github.com/ory/x/sqlxx"
"github.com/ory/x/urlx"
)

const (
Expand Down Expand Up @@ -146,13 +146,15 @@ type recoveryLinkForIdentity struct {
// 404: errorGeneric
// default: errorGeneric
func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
ctx := r.Context()

var p createRecoveryLinkForIdentityBody
if err := s.dx.Decode(r, &p, decoderx.HTTPJSONDecoder()); err != nil {
s.d.Writer().WriteError(w, r, err)
return
}

expiresIn := s.d.Config().SelfServiceLinkMethodLifespan(r.Context())
expiresIn := s.d.Config().SelfServiceLinkMethodLifespan(ctx)
if len(p.ExpiresIn) > 0 {
var err error
expiresIn, err = time.ParseDuration(p.ExpiresIn)
Expand All @@ -173,7 +175,7 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http.
return
}

id, err := s.d.IdentityPool().GetIdentity(r.Context(), p.IdentityID, identity.ExpandDefault)
id, err := s.d.IdentityPool().GetIdentity(ctx, p.IdentityID, identity.ExpandDefault)
if errors.Is(err, sqlcon.ErrNoRows) {
s.d.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("The requested identity id does not exist.").WithWrap(err)))
return
Expand All @@ -183,7 +185,7 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http.
}

token := NewAdminRecoveryToken(id.ID, req.ID, expiresIn)
if err := s.d.TransactionalPersisterProvider().Transaction(r.Context(), func(ctx context.Context, c *pop.Connection) error {
if err := s.d.TransactionalPersisterProvider().Transaction(ctx, func(ctx context.Context, c *pop.Connection) error {
if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(ctx, req); err != nil {
return err
}
Expand All @@ -194,6 +196,10 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http.
return
}

trace.SpanFromContext(ctx).AddEvent(
events.NewRecoveryInitiatedByAdmin(ctx, req.ID, id.ID, req.Type.String(), "link"),
)

s.d.Audit().
WithField("identity_id", id.ID).
WithSensitiveField("recovery_link_token", token).
Expand All @@ -202,7 +208,7 @@ func (s *Strategy) createRecoveryLinkForIdentity(w http.ResponseWriter, r *http.
s.d.Writer().Write(w, r, &recoveryLinkForIdentity{
ExpiresAt: req.ExpiresAt.UTC(),
RecoveryLink: urlx.CopyWithQuery(
urlx.AppendPaths(s.d.Config().SelfPublicURL(r.Context()), recovery.RouteSubmitFlow),
urlx.AppendPaths(s.d.Config().SelfPublicURL(ctx), recovery.RouteSubmitFlow),
url.Values{
"token": {token.Token},
"flow": {req.ID.String()},
Expand Down
56 changes: 34 additions & 22 deletions x/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,29 @@ import (
)

const (
SessionIssued semconv.Event = "SessionIssued"
SessionChanged semconv.Event = "SessionChanged"
SessionLifespanExtended semconv.Event = "SessionLifespanExtended"
SessionRevoked semconv.Event = "SessionRevoked"
SessionChecked semconv.Event = "SessionChecked"
SessionTokenizedAsJWT semconv.Event = "SessionTokenizedAsJWT"
RegistrationFailed semconv.Event = "RegistrationFailed"
RegistrationSucceeded semconv.Event = "RegistrationSucceeded"
LoginFailed semconv.Event = "LoginFailed"
LoginSucceeded semconv.Event = "LoginSucceeded"
SettingsFailed semconv.Event = "SettingsFailed"
SettingsSucceeded semconv.Event = "SettingsSucceeded"
RecoveryFailed semconv.Event = "RecoveryFailed"
RecoverySucceeded semconv.Event = "RecoverySucceeded"
VerificationFailed semconv.Event = "VerificationFailed"
VerificationSucceeded semconv.Event = "VerificationSucceeded"
IdentityCreated semconv.Event = "IdentityCreated"
IdentityUpdated semconv.Event = "IdentityUpdated"
IdentityDeleted semconv.Event = "IdentityDeleted"
WebhookDelivered semconv.Event = "WebhookDelivered"
WebhookSucceeded semconv.Event = "WebhookSucceeded"
WebhookFailed semconv.Event = "WebhookFailed"
SessionIssued semconv.Event = "SessionIssued"
SessionChanged semconv.Event = "SessionChanged"
SessionLifespanExtended semconv.Event = "SessionLifespanExtended"
SessionRevoked semconv.Event = "SessionRevoked"
SessionChecked semconv.Event = "SessionChecked"
SessionTokenizedAsJWT semconv.Event = "SessionTokenizedAsJWT"
RegistrationFailed semconv.Event = "RegistrationFailed"
RegistrationSucceeded semconv.Event = "RegistrationSucceeded"
LoginFailed semconv.Event = "LoginFailed"
LoginSucceeded semconv.Event = "LoginSucceeded"
SettingsFailed semconv.Event = "SettingsFailed"
SettingsSucceeded semconv.Event = "SettingsSucceeded"
RecoveryFailed semconv.Event = "RecoveryFailed"
RecoverySucceeded semconv.Event = "RecoverySucceeded"
RecoveryInitiatedByAdmin semconv.Event = "RecoveryInitiatedByAdmin"
VerificationFailed semconv.Event = "VerificationFailed"
VerificationSucceeded semconv.Event = "VerificationSucceeded"
IdentityCreated semconv.Event = "IdentityCreated"
IdentityUpdated semconv.Event = "IdentityUpdated"
IdentityDeleted semconv.Event = "IdentityDeleted"
WebhookDelivered semconv.Event = "WebhookDelivered"
WebhookSucceeded semconv.Event = "WebhookSucceeded"
WebhookFailed semconv.Event = "WebhookFailed"
)

const (
Expand Down Expand Up @@ -223,6 +224,17 @@ func NewRecoverySucceeded(ctx context.Context, flowID, identityID uuid.UUID, flo
)...)
}

func NewRecoveryInitiatedByAdmin(ctx context.Context, flowID, identityID uuid.UUID, flowType, method string) (string, trace.EventOption) {
return RecoveryInitiatedByAdmin.String(),
trace.WithAttributes(append(
semconv.AttributesFromContext(ctx),
attrSelfServiceFlowType(flowType),
semconv.AttrIdentityID(identityID),
attrSelfServiceMethodUsed(method),
attrFlowID(flowID),
)...)
}

func NewSettingsSucceeded(ctx context.Context, flowID, identityID uuid.UUID, flowType, method string) (string, trace.EventOption) {
return SettingsSucceeded.String(),
trace.WithAttributes(append(
Expand Down

0 comments on commit a7cdc3a

Please sign in to comment.