Skip to content

Commit

Permalink
fix: intra send location create event for 3b3 users (#603)
Browse files Browse the repository at this point in the history
**Describe the pull request**

This pull request resolves an issue that occurs when the 42 intranet
sends an event to the webhook processor to create a new location for an
anonymized (3b3-) user. By design, this should never happen on the intra
side, but when it does, it causes a significant increase in the size of
RabbitMQ. Therefore, I have implemented a protection mechanism to
prevent this.

**Checklist**

- [x] I have made the modifications or added tests related to my PR
- [x] I have run the tests and linters locally and they pass
- [x] I have added/updated the documentation for my RP
  • Loading branch information
42atomys authored May 30, 2024
1 parent 90e78fe commit eea9fd9
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 30 deletions.
86 changes: 56 additions & 30 deletions internal/models/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,42 +82,68 @@ func UserFirstOrCreateFromComplexLocation(ctx context.Context, l *duoapi.Locatio
func UserFirstOrCreateFromLocation(ctx context.Context, l *duoapi.Location[duoapi.LocationUser]) (*modelgen.User, error) {
u, err := client.User.Query().Where(user.DuoID(l.User.ID)).Only(ctx)
if err != nil {
if modelgen.IsNotFound(err) {
log.Debug().Str("login", l.User.Login).Int("duoID", l.User.ID).Msg("user don't exist import it with duopai")
duoUser, err := duoapi.UserGet(ctx, fmt.Sprint(l.User.ID))
if err != nil {
return nil, err
}
exist, err := userExist(ctx, l.User)
if err != nil {
return nil, err
}

id, err := client.User.Create().
SetEmail(duoUser.Email).
SetDuoID(l.User.ID).
SetDuoLogin(l.User.Login).
SetFirstName(duoUser.FirstName).
SetLastName(duoUser.LastName).
SetUsualFirstName(duoUser.UsualFirstName).
SetPoolMonth(duoUser.PoolMonth).
SetPoolYear(duoUser.PoolYear).
SetDuoAvatarURL(duoUser.Image.Link).
SetDuoAvatarSmallURL(duoUser.Image.Versions.Small).
SetIsStaff(duoUser.Staff).
SetIsAUser(false).
OnConflictColumns(user.FieldDuoID).
DoNothing().
ID(ctx)
if err != nil {
log.Debug().Err(err).Msg("error creating user")
return nil, err
}
u, err = client.User.Get(ctx, id)
if exist {
// User exist but dont match login / id
// Ensure to clean the old data before the re-creation
_, err := client.User.Delete().Where(user.And(user.DuoLogin(l.User.Login), user.IsAUser(false))).Exec(ctx)
if err != nil {
log.Debug().Err(err).Msg("failed to get user")
return nil, err
return nil, fmt.Errorf("cannot clean old login data: %w", err)
}
} else {
}

log.Debug().Str("login", l.User.Login).Int("duoID", l.User.ID).Msg("user don't exist import it with duopai")
duoUser, err := duoapi.UserGet(ctx, fmt.Sprint(l.User.ID))
if err != nil {
return nil, err
}

id, err := client.User.Create().
SetEmail(duoUser.Email).
SetDuoID(l.User.ID).
SetDuoLogin(l.User.Login).
SetFirstName(duoUser.FirstName).
SetLastName(duoUser.LastName).
SetUsualFirstName(duoUser.UsualFirstName).
SetPoolMonth(duoUser.PoolMonth).
SetPoolYear(duoUser.PoolYear).
SetDuoAvatarURL(duoUser.Image.Link).
SetDuoAvatarSmallURL(duoUser.Image.Versions.Small).
SetIsStaff(duoUser.Staff).
SetIsAUser(false).
OnConflictColumns(user.FieldDuoID).
DoNothing().
ID(ctx)
if err != nil {
log.Debug().Err(err).Msg("error creating user")
return nil, err
}
u, err = client.User.Get(ctx, id)
if err != nil {
log.Debug().Err(err).Msg("failed to get user")
return nil, err
}
}

return u, nil
}

// This function is only here to fix inconsistant data coming from intranet
func userExist(ctx context.Context, u duoapi.LocationUser) (bool, error) {
// Check by ID
n, err := client.User.Query().Where(
user.Or(
user.DuoID(u.ID),
user.DuoLogin(u.Login),
),
).Count(ctx)
if err != nil && !modelgen.IsNotFound(err) {
return false, err
}

return n > 0, nil
}
8 changes: 8 additions & 0 deletions internal/webhooks/location.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package webhooks
import (
"database/sql"
"errors"
"strings"

"github.com/rs/zerolog/log"

Expand Down Expand Up @@ -38,6 +39,11 @@ func (p *locationProcessor) Create(loc *duoapi.Location[duoapi.LocationUser], me
return err
}

// Skip location for anonymized users
if strings.HasPrefix(loc.User.Login, "3b3") {
return nil
}

// retrieve or create user in database from the location object received
user, err := modelsutils.UserFirstOrCreateFromLocation(p.ctx, loc)
if err != nil {
Expand Down Expand Up @@ -71,6 +77,7 @@ func (p *locationProcessor) Create(loc *duoapi.Location[duoapi.LocationUser], me

return err
}

func (p *locationProcessor) Close(loc *duoapi.Location[duoapi.LocationUser], metadata *duoapi.WebhookMetadata) error {
return modelsutils.WithTx(p.ctx, p.db, func(tx *generated.Tx) error {
// Close the location in database
Expand All @@ -90,6 +97,7 @@ func (p *locationProcessor) Close(loc *duoapi.Location[duoapi.LocationUser], met
return p.unlinkLocation(loc)
})
}

func (p *locationProcessor) Destroy(loc *duoapi.Location[duoapi.LocationUser], metadata *duoapi.WebhookMetadata) error {
// Delete the location in database
_, err := p.db.Location.Delete().Where(location.DuoID(loc.ID)).Exec(p.ctx)
Expand Down

0 comments on commit eea9fd9

Please sign in to comment.