feat(OIDC): support token revocation of V2 tokens (#6203)

This PR adds support for OAuth2 token revocation of V2 tokens.

Unlike with V1 tokens, it's now possible to revoke a token not only from the authorized client / client which the token was issued to, but rather from all trusted clients (audience)
This commit is contained in:
Livio Spring
2023-07-17 14:33:37 +02:00
committed by GitHub
parent ecf9835cb8
commit e1b3cda98a
17 changed files with 689 additions and 102 deletions

View File

@@ -1,11 +1,15 @@
package oidcsession
import "github.com/zitadel/zitadel/internal/eventstore"
import (
"github.com/zitadel/zitadel/internal/eventstore"
)
func RegisterEventMappers(es *eventstore.Eventstore) {
es.RegisterFilterEventMapper(AggregateType, AddedType, AddedEventMapper).
RegisterFilterEventMapper(AggregateType, AccessTokenAddedType, AccessTokenAddedEventMapper).
RegisterFilterEventMapper(AggregateType, RefreshTokenAddedType, RefreshTokenAddedEventMapper).
RegisterFilterEventMapper(AggregateType, RefreshTokenRenewedType, RefreshTokenRenewedEventMapper)
es.RegisterFilterEventMapper(AggregateType, AddedType, eventstore.GenericEventMapper[AddedEvent]).
RegisterFilterEventMapper(AggregateType, AccessTokenAddedType, eventstore.GenericEventMapper[AccessTokenAddedEvent]).
RegisterFilterEventMapper(AggregateType, AccessTokenRevokedType, eventstore.GenericEventMapper[AccessTokenRevokedEvent]).
RegisterFilterEventMapper(AggregateType, RefreshTokenAddedType, eventstore.GenericEventMapper[RefreshTokenAddedEvent]).
RegisterFilterEventMapper(AggregateType, RefreshTokenRenewedType, eventstore.GenericEventMapper[RefreshTokenRenewedEvent]).
RegisterFilterEventMapper(AggregateType, RefreshTokenRevokedType, eventstore.GenericEventMapper[RefreshTokenRevokedEvent])
}

View File

@@ -2,21 +2,20 @@ package oidcsession
import (
"context"
"encoding/json"
"time"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/repository"
)
const (
oidcSessionEventPrefix = "oidc_session."
AddedType = oidcSessionEventPrefix + "added"
AccessTokenAddedType = oidcSessionEventPrefix + "access_token.added"
AccessTokenRevokedType = oidcSessionEventPrefix + "access_token.revoked"
RefreshTokenAddedType = oidcSessionEventPrefix + "refresh_token.added"
RefreshTokenRenewedType = oidcSessionEventPrefix + "refresh_token.renewed"
RefreshTokenRevokedType = oidcSessionEventPrefix + "refresh_token.revoked"
)
type AddedEvent struct {
@@ -39,6 +38,10 @@ func (e *AddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func (e *AddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewAddedEvent(ctx context.Context,
aggregate *eventstore.Aggregate,
userID,
@@ -65,18 +68,6 @@ func NewAddedEvent(ctx context.Context,
}
}
func AddedEventMapper(event *repository.Event) (eventstore.Event, error) {
added := &AddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, added)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDCS-DG4gn", "unable to unmarshal oidc session added")
}
return added, nil
}
type AccessTokenAddedEvent struct {
eventstore.BaseEvent `json:"-"`
@@ -93,6 +84,10 @@ func (e *AccessTokenAddedEvent) UniqueConstraints() []*eventstore.EventUniqueCon
return nil
}
func (e *AccessTokenAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewAccessTokenAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
@@ -112,16 +107,33 @@ func NewAccessTokenAddedEvent(
}
}
func AccessTokenAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
added := &AccessTokenAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, added)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDCS-DSGn5", "unable to unmarshal access token added")
}
type AccessTokenRevokedEvent struct {
eventstore.BaseEvent `json:"-"`
}
return added, nil
func (e *AccessTokenRevokedEvent) Data() interface{} {
return e
}
func (e *AccessTokenRevokedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func (e *AccessTokenRevokedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewAccessTokenRevokedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *AccessTokenAddedEvent {
return &AccessTokenAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
AccessTokenRevokedType,
),
}
}
type RefreshTokenAddedEvent struct {
@@ -140,6 +152,10 @@ func (e *RefreshTokenAddedEvent) UniqueConstraints() []*eventstore.EventUniqueCo
return nil
}
func (e *RefreshTokenAddedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewRefreshTokenAddedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
@@ -159,18 +175,6 @@ func NewRefreshTokenAddedEvent(
}
}
func RefreshTokenAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
added := &RefreshTokenAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, added)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDCS-aW3gqq", "unable to unmarshal refresh token added")
}
return added, nil
}
type RefreshTokenRenewedEvent struct {
eventstore.BaseEvent `json:"-"`
@@ -186,6 +190,10 @@ func (e *RefreshTokenRenewedEvent) UniqueConstraints() []*eventstore.EventUnique
return nil
}
func (e *RefreshTokenRenewedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewRefreshTokenRenewedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
@@ -203,14 +211,31 @@ func NewRefreshTokenRenewedEvent(
}
}
func RefreshTokenRenewedEventMapper(event *repository.Event) (eventstore.Event, error) {
added := &RefreshTokenRenewedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, added)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDCS-SF3fc", "unable to unmarshal refresh token renewed")
}
return added, nil
type RefreshTokenRevokedEvent struct {
eventstore.BaseEvent `json:"-"`
}
func (e *RefreshTokenRevokedEvent) Data() interface{} {
return e
}
func (e *RefreshTokenRevokedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func (e *RefreshTokenRevokedEvent) SetBaseEvent(event *eventstore.BaseEvent) {
e.BaseEvent = *event
}
func NewRefreshTokenRevokedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
) *RefreshTokenRevokedEvent {
return &RefreshTokenRevokedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
RefreshTokenRevokedType,
),
}
}