Skip to content

Commit

Permalink
feat: add more resolution to events and collect client metrics (#3568)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Jul 10, 2023
1 parent 551c359 commit 466e66b
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 67 deletions.
29 changes: 26 additions & 3 deletions persistence/sql/persister_client.go
Expand Up @@ -6,6 +6,8 @@ package sql
import (
"context"

"github.com/ory/hydra/v2/x/events"

"github.com/gobuffalo/pop/v6"
"github.com/gofrs/uuid"

Expand Down Expand Up @@ -67,6 +69,11 @@ func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) (err er
} else if count == 0 {
return sqlcon.HandleError(sqlcon.ErrNoRows)
}

events.Trace(ctx, events.ClientUpdated,
events.WithClientID(cl.ID.String()),
events.WithClientName(cl.Name))

return sqlcon.HandleError(err)
})
}
Expand Down Expand Up @@ -103,19 +110,35 @@ func (p *Persister) CreateClient(ctx context.Context, c *client.Client) (err err
if c.LegacyClientID == "" {
c.LegacyClientID = c.ID.String()
}
return sqlcon.HandleError(p.CreateWithNetwork(ctx, c))
if err := sqlcon.HandleError(p.CreateWithNetwork(ctx, c)); err != nil {
return err
}

events.Trace(ctx, events.ClientCreated,
events.WithClientID(c.ID.String()),
events.WithClientName(c.Name))

return nil
}

func (p *Persister) DeleteClient(ctx context.Context, id string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteClient")
defer otelx.End(span, &err)

_, err = p.GetConcreteClient(ctx, id)
c, err := p.GetConcreteClient(ctx, id)
if err != nil {
return err
}

return sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("id = ?", id).Delete(&client.Client{}))
if err := sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("id = ?", id).Delete(&client.Client{})); err != nil {
return err
}

events.Trace(ctx, events.ClientDeleted,
events.WithClientID(c.ID.String()),
events.WithClientName(c.Name))

return nil
}

func (p *Persister) GetClients(ctx context.Context, filters client.Filter) (_ []client.Client, err error) {
Expand Down
146 changes: 84 additions & 62 deletions persistence/sql/persister_oauth2.go
Expand Up @@ -5,14 +5,18 @@ package sql

import (
"context"
"crypto/sha256"
"crypto/sha512"
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"net/url"
"strings"
"time"

"go.opentelemetry.io/otel/trace"

"github.com/gofrs/uuid"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
Expand Down Expand Up @@ -363,11 +367,15 @@ func (p *Persister) InvalidateAuthorizeCodeSession(ctx context.Context, signatur
)
}

func (p *Persister) CreateAccessTokenSession(ctx context.Context, signature string, requester fosite.Requester) error {
events.Trace(ctx, events.AccessTokenIssued, events.WithRequest(requester))
return otelx.WithSpan(ctx, "persistence.sql.CreateAccessTokenSession", func(ctx context.Context) error {
return p.createSession(ctx, signature, requester, sqlTableAccess)
})
func (p *Persister) CreateAccessTokenSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateAccessTokenSession")
defer otelx.End(span, &err)

events.Trace(ctx, events.AccessTokenIssued,
append(toEventOptions(requester), events.WithGrantType(requester.GetRequestForm().Get("grant_type")))...,
)

return p.createSession(ctx, signature, requester, sqlTableAccess)
}

func (p *Persister) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) {
Expand All @@ -376,17 +384,31 @@ func (p *Persister) GetAccessTokenSession(ctx context.Context, signature string,
return p.findSessionBySignature(ctx, signature, session, sqlTableAccess)
}

func (p *Persister) DeleteAccessTokenSession(ctx context.Context, signature string) error {
return otelx.WithSpan(ctx, "persistence.sql.DeleteAccessTokenSession", func(ctx context.Context) error {
return p.deleteSessionBySignature(ctx, signature, sqlTableAccess)
})
func (p *Persister) DeleteAccessTokenSession(ctx context.Context, signature string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteAccessTokenSession")
defer otelx.End(span, &err)
return p.deleteSessionBySignature(ctx, signature, sqlTableAccess)
}

func (p *Persister) CreateRefreshTokenSession(ctx context.Context, signature string, requester fosite.Requester) error {
events.Trace(ctx, events.RefreshTokenIssued, events.WithRequest(requester))
return otelx.WithSpan(ctx, "persistence.sql.CreateRefreshTokenSession", func(ctx context.Context) error {
return p.createSession(ctx, signature, requester, sqlTableRefresh)
})
func toEventOptions(requester fosite.Requester) []trace.EventOption {
sub := ""
if requester.GetSession() != nil {
hash := sha256.Sum256([]byte(requester.GetSession().GetSubject()))
sub = hex.EncodeToString(hash[:])
}
return []trace.EventOption{
events.WithGrantType(requester.GetRequestForm().Get("grant_type")),
events.WithSubject(sub),
events.WithRequest(requester),
events.WithClientID(requester.GetClient().GetID()),
}
}

func (p *Persister) CreateRefreshTokenSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteCreateRefreshTokenSessionAccessTokenSession")
defer otelx.End(span, &err)
events.Trace(ctx, events.RefreshTokenIssued, toEventOptions(requester)...)
return p.createSession(ctx, signature, requester, sqlTableRefresh)
}

func (p *Persister) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) {
Expand All @@ -395,17 +417,17 @@ func (p *Persister) GetRefreshTokenSession(ctx context.Context, signature string
return p.findSessionBySignature(ctx, signature, session, sqlTableRefresh)
}

func (p *Persister) DeleteRefreshTokenSession(ctx context.Context, signature string) error {
return otelx.WithSpan(ctx, "persistence.sql.DeleteRefreshTokenSession", func(ctx context.Context) error {
return p.deleteSessionBySignature(ctx, signature, sqlTableRefresh)
})
func (p *Persister) DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRefreshTokenSession")
defer otelx.End(span, &err)
return p.deleteSessionBySignature(ctx, signature, sqlTableRefresh)
}

func (p *Persister) CreateOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) error {
events.Trace(ctx, events.IdentityTokenIssued, events.WithRequest(requester))
return otelx.WithSpan(ctx, "persistence.sql.CreateOpenIDConnectSession", func(ctx context.Context) error {
return p.createSession(ctx, signature, requester, sqlTableOpenID)
})
func (p *Persister) CreateOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateOpenIDConnectSession")
defer otelx.End(span, &err)
events.Trace(ctx, events.IdentityTokenIssued, toEventOptions(requester)...)
return p.createSession(ctx, signature, requester, sqlTableOpenID)
}

func (p *Persister) GetOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) (_ fosite.Requester, err error) {
Expand All @@ -414,10 +436,10 @@ func (p *Persister) GetOpenIDConnectSession(ctx context.Context, signature strin
return p.findSessionBySignature(ctx, signature, requester.GetSession(), sqlTableOpenID)
}

func (p *Persister) DeleteOpenIDConnectSession(ctx context.Context, signature string) error {
return otelx.WithSpan(ctx, "persistence.sql.DeleteOpenIDConnectSession", func(ctx context.Context) error {
return p.deleteSessionBySignature(ctx, signature, sqlTableOpenID)
})
func (p *Persister) DeleteOpenIDConnectSession(ctx context.Context, signature string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteOpenIDConnectSession")
defer otelx.End(span, &err)
return p.deleteSessionBySignature(ctx, signature, sqlTableOpenID)
}

func (p *Persister) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (_ fosite.Requester, err error) {
Expand All @@ -426,34 +448,34 @@ func (p *Persister) GetPKCERequestSession(ctx context.Context, signature string,
return p.findSessionBySignature(ctx, signature, session, sqlTablePKCE)
}

func (p *Persister) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error {
return otelx.WithSpan(ctx, "persistence.sql.CreatePKCERequestSession", func(ctx context.Context) error {
return p.createSession(ctx, signature, requester, sqlTablePKCE)
})
func (p *Persister) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreatePKCERequestSession")
defer otelx.End(span, &err)
return p.createSession(ctx, signature, requester, sqlTablePKCE)
}

func (p *Persister) DeletePKCERequestSession(ctx context.Context, signature string) error {
return otelx.WithSpan(ctx, "persistence.sql.DeletePKCERequestSession", func(ctx context.Context) error {
return p.deleteSessionBySignature(ctx, signature, sqlTablePKCE)
})
func (p *Persister) DeletePKCERequestSession(ctx context.Context, signature string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeletePKCERequestSession")
defer otelx.End(span, &err)
return p.deleteSessionBySignature(ctx, signature, sqlTablePKCE)
}

func (p *Persister) RevokeRefreshToken(ctx context.Context, id string) error {
return otelx.WithSpan(ctx, "persistence.sql.RevokeRefreshToken", func(ctx context.Context) error {
return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh)
})
func (p *Persister) RevokeRefreshToken(ctx context.Context, id string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeRefreshToken")
defer otelx.End(span, &err)
return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh)
}

func (p *Persister) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, id string, _ string) error {
return otelx.WithSpan(ctx, "persistence.sql.RevokeRefreshTokenMaybeGracePeriod", func(ctx context.Context) error {
return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh)
})
func (p *Persister) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, id string, _ string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeRefreshTokenMaybeGracePeriod")
defer otelx.End(span, &err)
return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh)
}

func (p *Persister) RevokeAccessToken(ctx context.Context, id string) error {
return otelx.WithSpan(ctx, "persistence.sql.RevokeAccessToken", func(ctx context.Context) error {
return p.deleteSessionByRequestID(ctx, id, sqlTableAccess)
})
func (p *Persister) RevokeAccessToken(ctx context.Context, id string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeAccessToken")
defer otelx.End(span, &err)
return p.deleteSessionByRequestID(ctx, id, sqlTableAccess)
}

func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int, table tableName, lifespan time.Duration) (err error) {
Expand Down Expand Up @@ -490,23 +512,23 @@ func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time,
return sqlcon.HandleError(err)
}

func (p *Persister) FlushInactiveAccessTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) error {
return otelx.WithSpan(ctx, "persistence.sql.FlushInactiveAccessTokens", func(ctx context.Context) error {
return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableAccess, p.config.GetAccessTokenLifespan(ctx))
})
func (p *Persister) FlushInactiveAccessTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveAccessTokens")
defer otelx.End(span, &err)
return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableAccess, p.config.GetAccessTokenLifespan(ctx))
}

func (p *Persister) FlushInactiveRefreshTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) error {
return otelx.WithSpan(ctx, "persistence.sql.FlushInactiveRefreshTokens", func(ctx context.Context) error {
return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableRefresh, p.config.GetRefreshTokenLifespan(ctx))
})
func (p *Persister) FlushInactiveRefreshTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveRefreshTokens")
defer otelx.End(span, &err)
return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableRefresh, p.config.GetRefreshTokenLifespan(ctx))
}

func (p *Persister) DeleteAccessTokens(ctx context.Context, clientID string) error {
return otelx.WithSpan(ctx, "persistence.sql.DeleteAccessTokens", func(ctx context.Context) error {
/* #nosec G201 table is static */
return sqlcon.HandleError(
p.QueryWithNetwork(ctx).Where("client_id=?", clientID).Delete(&OAuth2RequestSQL{Table: sqlTableAccess}),
)
})
func (p *Persister) DeleteAccessTokens(ctx context.Context, clientID string) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteAccessTokens")
defer otelx.End(span, &err)
/* #nosec G201 table is static */
return sqlcon.HandleError(
p.QueryWithNetwork(ctx).Where("client_id=?", clientID).Delete(&OAuth2RequestSQL{Table: sqlTableAccess}),
)
}
31 changes: 29 additions & 2 deletions x/events/events.go
Expand Up @@ -29,6 +29,15 @@ const (
// ConsentRevoked will be emitted when the user revokes a consent request.
ConsentRevoked semconv.Event = "OAuth2ConsentRevoked"

// ClientCreated will be emitted when a client is created.
ClientCreated semconv.Event = "OAuth2ClientCreated"

// ClientDeleted will be emitted when a client is deleted.
ClientDeleted semconv.Event = "OAuth2ClientDeleted"

// ClientUpdated will be emitted when a client is updated.
ClientUpdated semconv.Event = "OAuth2ClientUpdated"

// AccessTokenIssued will be emitted by requests to POST /oauth2/token in case the request was successful.
AccessTokenIssued semconv.Event = "OAuth2AccessTokenIssued" //nolint:gosec

Expand All @@ -49,15 +58,33 @@ const (
)

const (
attributeKeyOAuth2ClientID = "OAuth2ClientID"
attributeKeyOAuth2Subject = "OAuth2Subject"
attributeKeyOAuth2ClientName = "OAuth2ClientName"
attributeKeyOAuth2ClientID = "OAuth2ClientID"
attributeKeyOAuth2Subject = "OAuth2Subject"
attributeKeyOAuth2GrantType = "OAuth2GrantType"
attributeKeyOAuth2TokenFormat = "OAuth2TokenFormat" //nolint:gosec
)

// WithTokenFormat emits the token format as part of the event.
func WithTokenFormat(format string) trace.EventOption {
return trace.WithAttributes(otelattr.String(attributeKeyOAuth2TokenFormat, format))
}

// WithGrantType emits the token format as part of the event.
func WithGrantType(grantType string) trace.EventOption {
return trace.WithAttributes(otelattr.String(attributeKeyOAuth2GrantType, grantType))
}

// WithClientID emits the client ID as part of the event.
func WithClientID(clientID string) trace.EventOption {
return trace.WithAttributes(otelattr.String(attributeKeyOAuth2ClientID, clientID))
}

// WithClientName emits the client name as part of the event.
func WithClientName(clientID string) trace.EventOption {
return trace.WithAttributes(otelattr.String(attributeKeyOAuth2ClientName, clientID))
}

// WithSubject emits the subject as part of the event.
func WithSubject(subject string) trace.EventOption {
return trace.WithAttributes(otelattr.String(attributeKeyOAuth2Subject, subject))
Expand Down

0 comments on commit 466e66b

Please sign in to comment.