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

@@ -20,9 +20,11 @@ type OIDCSessionWriteModel struct {
AuthMethods []domain.UserAuthMethodType
AuthTime time.Time
State domain.OIDCSessionState
AccessTokenID string
AccessTokenCreation time.Time
AccessTokenExpiration time.Time
RefreshTokenID string
RefreshToken string
RefreshTokenExpiration time.Time
RefreshTokenIdleExpiration time.Time
@@ -46,10 +48,14 @@ func (wm *OIDCSessionWriteModel) Reduce() error {
wm.reduceAdded(e)
case *oidcsession.AccessTokenAddedEvent:
wm.reduceAccessTokenAdded(e)
case *oidcsession.AccessTokenRevokedEvent:
wm.reduceAccessTokenRevoked(e)
case *oidcsession.RefreshTokenAddedEvent:
wm.reduceRefreshTokenAdded(e)
case *oidcsession.RefreshTokenRenewedEvent:
wm.reduceRefreshTokenRenewed(e)
case *oidcsession.RefreshTokenRevokedEvent:
wm.reduceRefreshTokenRevoked(e)
}
}
return wm.WriteModel.Reduce()
@@ -65,6 +71,7 @@ func (wm *OIDCSessionWriteModel) Query() *eventstore.SearchQueryBuilder {
oidcsession.AccessTokenAddedType,
oidcsession.RefreshTokenAddedType,
oidcsession.RefreshTokenRenewedType,
oidcsession.RefreshTokenRevokedType,
).
Builder()
@@ -91,9 +98,15 @@ func (wm *OIDCSessionWriteModel) reduceAdded(e *oidcsession.AddedEvent) {
}
func (wm *OIDCSessionWriteModel) reduceAccessTokenAdded(e *oidcsession.AccessTokenAddedEvent) {
wm.AccessTokenID = e.ID
wm.AccessTokenExpiration = e.CreationDate().Add(e.Lifetime)
}
func (wm *OIDCSessionWriteModel) reduceAccessTokenRevoked(e *oidcsession.AccessTokenRevokedEvent) {
wm.AccessTokenID = ""
wm.AccessTokenExpiration = e.CreationDate()
}
func (wm *OIDCSessionWriteModel) reduceRefreshTokenAdded(e *oidcsession.RefreshTokenAddedEvent) {
wm.RefreshTokenID = e.ID
wm.RefreshTokenExpiration = e.CreationDate().Add(e.Lifetime)
@@ -105,6 +118,14 @@ func (wm *OIDCSessionWriteModel) reduceRefreshTokenRenewed(e *oidcsession.Refres
wm.RefreshTokenIdleExpiration = e.CreationDate().Add(e.IdleLifetime)
}
func (wm *OIDCSessionWriteModel) reduceRefreshTokenRevoked(e *oidcsession.RefreshTokenRevokedEvent) {
wm.RefreshTokenID = ""
wm.RefreshTokenExpiration = e.CreationDate()
wm.RefreshTokenIdleExpiration = e.CreationDate()
wm.AccessTokenID = ""
wm.AccessTokenExpiration = e.CreationDate()
}
func (wm *OIDCSessionWriteModel) CheckRefreshToken(refreshTokenID string) error {
if wm.State != domain.OIDCSessionStateActive {
return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-s3hjk", "Errors.OIDCSession.RefreshTokenInvalid")
@@ -118,3 +139,29 @@ func (wm *OIDCSessionWriteModel) CheckRefreshToken(refreshTokenID string) error
}
return nil
}
func (wm *OIDCSessionWriteModel) CheckAccessToken(accessTokenID string) error {
if wm.State != domain.OIDCSessionStateActive {
return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-KL2pk", "Errors.OIDCSession.Token.Invalid")
}
if wm.AccessTokenID != accessTokenID {
return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-JLKW2", "Errors.OIDCSession.Token.Invalid")
}
if wm.AccessTokenExpiration.Before(time.Now()) {
return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-3j3md", "Errors.OIDCSession.Token.Invalid")
}
return nil
}
func (wm *OIDCSessionWriteModel) CheckClient(clientID string) error {
for _, aud := range wm.Audience {
if aud == clientID {
return nil
}
}
return caos_errs.ThrowPreconditionFailed(nil, "OIDCS-SKjl3", "Errors.OIDCSession.InvalidClient")
}
func (wm *OIDCSessionWriteModel) OIDCRefreshTokenID(refreshTokenID string) string {
return wm.AggregateID + TokenDelimiter + refreshTokenID
}