Merge pull request #3007 from opencloud-eu/dependabot/go_modules/github.com/coreos/go-oidc/v3-3.19.0

build(deps): bump github.com/coreos/go-oidc/v3 from 3.18.0 to 3.19.0
This commit is contained in:
Ralf Haferkamp
2026-06-24 12:12:03 +02:00
committed by GitHub
6 changed files with 246 additions and 49 deletions

2
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/beevik/etree v1.6.0
github.com/blevesearch/bleve/v2 v2.6.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.18.0
github.com/coreos/go-oidc/v3 v3.19.0
github.com/cs3org/go-cs3apis v0.0.0-20260424072047-8d9ef7076ae9
github.com/davidbyttow/govips/v2 v2.18.0
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8

4
go.sum
View File

@@ -240,8 +240,8 @@ github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6a
github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc/v3 v3.18.0 h1:V9orjXynvu5wiC9SemFTWnG4F45v403aIcjWo0d41+A=
github.com/coreos/go-oidc/v3 v3.18.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4=
github.com/coreos/go-oidc/v3 v3.19.0 h1:F/xyOi3x1UnG1U27YVnM1N6bHiL1K2upi6U/0qr8r+I=
github.com/coreos/go-oidc/v3 v3.19.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=

View File

@@ -238,6 +238,7 @@ func (r *RemoteKeySet) updateKeys() ([]jose.JSONWebKey, error) {
if err != nil {
return nil, fmt.Errorf("oidc: can't create request: %v", err)
}
req.Header.Set("Cache-Control", "no-cache")
resp, err := doRequest(r.ctx, req)
if err != nil {

187
vendor/github.com/coreos/go-oidc/v3/oidc/logout.go generated vendored Normal file
View File

@@ -0,0 +1,187 @@
package oidc
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
)
// LogoutToken represents a verified token from a Back-Channel Logout. Use
// [IDTokenVerifier.VerifyLogout] within a POST handler to receive and validate
// a token.
//
// See the ./example/logout at the top-level of this repo for a full example
// application.
type LogoutToken struct {
// The required token ID claim ("jti"). When processing this token for
// logout, applications should validate that no recent token with the same
// value has been processed.
TokenID string
// The unique identifier of the user that this logout token is for. This
// will match the subject value of the ID Token.
//
// If not set, SessionID will be.
Subject string
// The "iss" claim. This is validated against the provider URL unless
// explicitly skipped through SkipIssuerCheck.
Issuer string
// The Client ID this logout token is for. Validated against the config
// unless SkipClientIDCheck is provided.
Audience []string
// When this token was issued.
IssuedAt time.Time
// When this token expires. Validated unless SkipExpiryCheck is provided.
Expiry time.Time
// Optional session ID claim ("sid").
//
// The exact semantics of session IDs very between identity providers. Use
// your provider's documentation to determine what this correlates to and
// how it should be handled.
SessionID string
claims []byte
}
// Claims unmarshals the raw JSON payload of the Logout Token into a provided
// struct. This can be used to access field not exposed by the LogoutToken
// fields.
//
// logoutToken, err := idTokenVerifier.VerifyLogout(ctx, rawLogoutToken)
// if err != nil{
// // ...
// }
// var claims struct {
// TraceID string `json:"trace_id"`
// }
// if err := logoutToken.Claims(&claims); err != nil {
// // ...
// }
func (l *LogoutToken) Claims(v any) error {
if l.claims == nil {
return errors.New("oidc: claims not set")
}
return json.Unmarshal(l.claims, v)
}
// https://openid.net/specs/openid-connect-backchannel-1_0.html#LogoutToken
type logoutTokenJSON struct {
Issuer string `json:"iss"`
Subject string `json:"sub"`
Audience audience `json:"aud"`
Expiry jsonTime `json:"exp"`
IssuedAt jsonTime `json:"iat"`
JTI string `json:"jti"`
Events struct {
Logout json.RawMessage `json:"http://schemas.openid.net/event/backchannel-logout"`
}
SessionID string `json:"sid"`
// Nonce is parsed as a raw message so its mere presence can be detected.
// The spec requires logout tokens to not contain a nonce claim, regardless
// of its value.
Nonce json.RawMessage `json:"nonce"`
}
// VerifyLogout validates a back-channel logout token. Logout tokens are
// received by the relying party (this package) from the identity provider at a
// preconfigured "backchannel_logout_uri" through a POST. Then on certain
// events, such as RP-Initiated Logout, the identity provider will send a signed
// token indicating that sessions for a specific user should be terminated.
//
// To support back-channel logout within your app, register a POST endpoint and
// verify the token:
//
// oidcConfig := &oidc.Config{
// ClientID: clientID,
// }
// verifier := provider.Verifier(oidcConfig)
//
// mux.HandleFunc("POST /logout", func(w http.ResponseWriter, r *http.Reequest) {
// rawLogoutToken := r.PostFormValue("logout_token")
// if rawLogoutToken == "" {
// // ...
// }
// logoutToken, err := verifier.VerifyLogout(r.Context(), rawLogoutToken)
// if err != nil {
// // ...
// }
// // Use fields in the logoutToken to determine what sessions to
// // terminate.
//
// })
//
// Back-channel logout spec: https://openid.net/specs/openid-connect-backchannel-1_0.html
//
// RP-initiated logout spec: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
func (v *IDTokenVerifier) VerifyLogout(ctx context.Context, rawLogoutToken string) (*LogoutToken, error) {
payload, _, err := v.verifyJWT(ctx, rawLogoutToken)
if err != nil {
return nil, err
}
var logoutToken logoutTokenJSON
if err := json.Unmarshal(payload, &logoutToken); err != nil {
return nil, fmt.Errorf("oidc: parsing logout token payload: %v", err)
}
if len(logoutToken.Events.Logout) == 0 {
return nil, fmt.Errorf("oidc: logout token missing required http://schemas.openid.net/event/backchannel-logout event")
}
// A logout token MUST NOT contain a nonce claim. This prevents an ID token
// from being replayed as a logout token.
if len(logoutToken.Nonce) != 0 {
return nil, fmt.Errorf("oidc: logout token must not contain a 'nonce' claim")
}
t := &LogoutToken{
Issuer: logoutToken.Issuer,
Subject: logoutToken.Subject,
Audience: logoutToken.Audience,
IssuedAt: time.Time(logoutToken.IssuedAt),
Expiry: time.Time(logoutToken.Expiry),
SessionID: logoutToken.SessionID,
TokenID: logoutToken.JTI,
claims: payload,
}
if t.TokenID == "" {
return nil, fmt.Errorf("oidc: logout token missing required claim 'jti'")
}
if t.Expiry.IsZero() {
return nil, fmt.Errorf("oidc: logout token must contain an 'exp' claim")
}
// A logout token MUST contain a 'sub' claim, a 'sid' claim, or both.
if t.Subject == "" && t.SessionID == "" {
return nil, fmt.Errorf("oidc: logout token must contain a 'sub' claim, a 'sid' claim, or both")
}
if !v.config.SkipIssuerCheck && t.Issuer != v.issuer {
return nil, fmt.Errorf("oidc: logout token issued by a different provider, expected %q, got %q", v.issuer, t.Issuer)
}
if !v.config.SkipClientIDCheck {
if v.config.ClientID != "" {
if !contains(t.Audience, v.config.ClientID) {
return nil, fmt.Errorf("oidc: expected logout token audience %q got %q", v.config.ClientID, t.Audience)
}
} else {
return nil, fmt.Errorf("oidc: invalid configuration, clientID must be provided or SkipClientIDCheck must be set")
}
}
// If a SkipExpiryCheck is false, make sure token is not expired.
if !v.config.SkipExpiryCheck {
now := time.Now
if v.config.Now != nil {
now = v.config.Now
}
nowTime := now()
if t.Expiry.Before(nowTime) {
return nil, &TokenExpiredError{Expiry: t.Expiry}
}
}
return t, nil
}

View File

@@ -17,9 +17,10 @@ const (
issuerGoogleAccountsNoScheme = "accounts.google.com"
)
// TokenExpiredError indicates that Verify failed because the token was expired. This
// error does NOT indicate that the token is not also invalid for other reasons. Other
// checks might have failed if the expiration check had not failed.
// TokenExpiredError indicates that Verify or VerifyLogout failed because the
// token was expired. This error does NOT indicate that the token is not also
// invalid for other reasons. Other checks might have failed if the expiration
// check had not failed.
type TokenExpiredError struct {
// Expiry is the time when the token expired.
Expiry time.Time
@@ -44,7 +45,7 @@ type KeySet interface {
VerifySignature(ctx context.Context, jwt string) (payload []byte, err error)
}
// IDTokenVerifier provides verification for ID Tokens.
// IDTokenVerifier provides verification for ID Tokens and Logout Tokens.
type IDTokenVerifier struct {
keySet KeySet
config *Config
@@ -203,48 +204,9 @@ func resolveDistributedClaim(ctx context.Context, verifier *IDTokenVerifier, src
//
// token, err := verifier.Verify(ctx, rawIDToken)
func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDToken, error) {
var supportedSigAlgs []jose.SignatureAlgorithm
for _, alg := range v.config.SupportedSigningAlgs {
supportedSigAlgs = append(supportedSigAlgs, jose.SignatureAlgorithm(alg))
}
if len(supportedSigAlgs) == 0 {
// If no algorithms were specified by both the config and discovery, default
// to the one mandatory algorithm "RS256".
supportedSigAlgs = []jose.SignatureAlgorithm{jose.RS256}
}
if v.config.InsecureSkipSignatureCheck {
// "none" is a required value to even parse a JWT with the "none" algorithm
// using go-jose.
supportedSigAlgs = append(supportedSigAlgs, "none")
}
// Parse and verify the signature first. This at least forces the user to have
// a valid, signed ID token before we do any other processing.
jws, err := jose.ParseSigned(rawIDToken, supportedSigAlgs)
payload, sig, err := v.verifyJWT(ctx, rawIDToken)
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
}
switch len(jws.Signatures) {
case 0:
return nil, fmt.Errorf("oidc: id token not signed")
case 1:
default:
return nil, fmt.Errorf("oidc: multiple signatures on id token not supported")
}
sig := jws.Signatures[0]
var payload []byte
if v.config.InsecureSkipSignatureCheck {
// Yolo mode.
payload = jws.UnsafePayloadWithoutVerification()
} else {
// The JWT is attached here for the happy path to avoid the verifier from
// having to parse the JWT twice.
ctx = context.WithValue(ctx, parsedJWTKey, jws)
payload, err = v.keySet.VerifySignature(ctx, rawIDToken)
if err != nil {
return nil, fmt.Errorf("failed to verify signature: %v", err)
}
return nil, err
}
var token idToken
if err := json.Unmarshal(payload, &token); err != nil {
@@ -336,3 +298,50 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
func Nonce(nonce string) oauth2.AuthCodeOption {
return oauth2.SetAuthURLParam("nonce", nonce)
}
func (v *IDTokenVerifier) verifyJWT(ctx context.Context, rawIDToken string) ([]byte, jose.Signature, error) {
var supportedSigAlgs []jose.SignatureAlgorithm
for _, alg := range v.config.SupportedSigningAlgs {
supportedSigAlgs = append(supportedSigAlgs, jose.SignatureAlgorithm(alg))
}
if len(supportedSigAlgs) == 0 {
// If no algorithms were specified by both the config and discovery, default
// to the one mandatory algorithm "RS256".
supportedSigAlgs = []jose.SignatureAlgorithm{jose.RS256}
}
if v.config.InsecureSkipSignatureCheck {
// "none" is a required value to even parse a JWT with the "none" algorithm
// using go-jose.
supportedSigAlgs = append(supportedSigAlgs, "none")
}
// Parse and verify the signature first. This at least forces the user to have
// a valid, signed ID token before we do any other processing.
jws, err := jose.ParseSigned(rawIDToken, supportedSigAlgs)
if err != nil {
return nil, jose.Signature{}, fmt.Errorf("oidc: malformed jwt: %v", err)
}
switch len(jws.Signatures) {
case 0:
return nil, jose.Signature{}, fmt.Errorf("oidc: id token not signed")
case 1:
default:
return nil, jose.Signature{}, fmt.Errorf("oidc: multiple signatures on id token not supported")
}
sig := jws.Signatures[0]
var payload []byte
if v.config.InsecureSkipSignatureCheck {
// Yolo mode.
payload = jws.UnsafePayloadWithoutVerification()
} else {
// The JWT is attached here for the happy path to avoid the verifier from
// having to parse the JWT twice.
ctx = context.WithValue(ctx, parsedJWTKey, jws)
payload, err = v.keySet.VerifySignature(ctx, rawIDToken)
if err != nil {
return nil, jose.Signature{}, fmt.Errorf("failed to verify signature: %v", err)
}
}
return payload, sig, nil
}

2
vendor/modules.txt vendored
View File

@@ -292,7 +292,7 @@ github.com/containerd/log
# github.com/containerd/platforms v1.0.0-rc.2
## explicit; go 1.20
github.com/containerd/platforms
# github.com/coreos/go-oidc/v3 v3.18.0
# github.com/coreos/go-oidc/v3 v3.19.0
## explicit; go 1.25.0
github.com/coreos/go-oidc/v3/oidc
# github.com/coreos/go-semver v0.3.1