feat: token revocation and OP certification (#2594)

* fix: try using only user session if no user is set (id_token_hint) on prompt none

* fix caos errors As implementation

* implement request mode

* return explicit error on invalid refresh token use

* begin token revocation

* token revocation

* tests

* tests

* cleanup

* set op config

* add revocation endpoint to config

* add revocation endpoint to config

* migration version

* error handling in token revocation

* migration version

* update oidc lib to 1.0.0
This commit is contained in:
Livio Amstutz
2021-11-03 08:35:24 +01:00
committed by GitHub
parent 8df5614e4d
commit fc6154cffc
25 changed files with 638 additions and 236 deletions

View File

@@ -116,6 +116,9 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok
refreshToken, req.GetAudience(), req.GetScopes(), authMethodsReferences, o.defaultAccessTokenLifetime,
o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client
if err != nil {
if errors.IsErrorInvalidArgument(err) {
err = oidc.ErrInvalidGrant().WithParent(err)
}
return "", "", time.Time{}, err
}
return resp.TokenID, token, resp.Expiration, nil
@@ -162,6 +165,35 @@ func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID strin
return err
}
func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID string) *oidc.Error {
refreshToken, err := o.repo.RefreshTokenByID(ctx, token)
if err == nil {
if refreshToken.ClientID != clientID {
return oidc.ErrInvalidClient().WithDescription("token was not issued for this client")
}
_, err = o.command.RevokeRefreshToken(ctx, refreshToken.UserID, refreshToken.ResourceOwner, refreshToken.ID)
if errors.IsNotFound(err) {
return nil
}
return oidc.ErrServerError().WithParent(err)
}
accessToken, err := o.repo.TokenByID(ctx, userID, token)
if err != nil {
if errors.IsNotFound(err) {
return nil
}
return oidc.ErrServerError().WithParent(err)
}
if accessToken.ApplicationID != clientID {
return oidc.ErrInvalidClient().WithDescription("token was not issued for this client")
}
_, err = o.command.RevokeAccessToken(ctx, userID, accessToken.ResourceOwner, accessToken.ID)
if err == nil || errors.IsNotFound(err) {
return nil
}
return oidc.ErrServerError().WithParent(err)
}
func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey) {
o.repo.GetSigningKey(ctx, keyCh, o.signingKeyAlgorithm)
}

View File

@@ -81,6 +81,10 @@ func (a *AuthRequest) GetResponseType() oidc.ResponseType {
return ResponseTypeToOIDC(a.oidc().ResponseType)
}
func (a *AuthRequest) GetResponseMode() oidc.ResponseMode {
return ""
}
func (a *AuthRequest) GetScopes() []string {
return a.oidc().Scopes
}

View File

@@ -44,6 +44,7 @@ type EndpointConfig struct {
Token *Endpoint
Introspection *Endpoint
Userinfo *Endpoint
Revocation *Endpoint
EndSession *Endpoint
Keys *Endpoint
}
@@ -76,6 +77,8 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, command *command.C
}
copy(config.OPConfig.CryptoKey[:], cryptoKey)
config.OPConfig.CodeMethodS256 = true
config.OPConfig.AuthMethodPost = true
config.OPConfig.AuthMethodPrivateKeyJWT = true
config.OPConfig.GrantTypeRefreshToken = true
supportedLanguages, err := getSupportedLanguages()
logging.Log("OIDC-GBd3t").OnError(err).Panic("cannot get supported languages")
@@ -96,6 +99,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, command *command.C
op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)),
op.WithCustomIntrospectionEndpoint(op.NewEndpointWithURL(config.Endpoints.Introspection.Path, config.Endpoints.Introspection.URL)),
op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)),
op.WithCustomRevocationEndpoint(op.NewEndpointWithURL(config.Endpoints.Revocation.Path, config.Endpoints.Revocation.URL)),
op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)),
op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)),
)