Переглянути джерело

oidc refresh token: validate nonce only if set

As clarified in OpenID core spec errata 2, section 12.2

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 1 рік тому
батько
коміт
64a2f7aa4f
2 змінених файлів з 10 додано та 6 видалено
  1. 6 4
      internal/httpd/oidc.go
  2. 4 2
      internal/httpd/oidc_test.go

+ 6 - 4
internal/httpd/oidc.go

@@ -16,6 +16,7 @@ package httpd
 
 
 import (
 import (
 	"context"
 	"context"
+	"encoding/hex"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
@@ -203,7 +204,7 @@ type oidcPendingAuth struct {
 func newOIDCPendingAuth(audience tokenAudience) oidcPendingAuth {
 func newOIDCPendingAuth(audience tokenAudience) oidcPendingAuth {
 	return oidcPendingAuth{
 	return oidcPendingAuth{
 		State:    xid.New().String(),
 		State:    xid.New().String(),
-		Nonce:    xid.New().String(),
+		Nonce:    hex.EncodeToString(util.GenerateRandomBytes(20)),
 		Audience: audience,
 		Audience: audience,
 		IssuedAt: util.GetTimeAsMsSinceEpoch(time.Now()),
 		IssuedAt: util.GetTimeAsMsSinceEpoch(time.Now()),
 	}
 	}
@@ -345,14 +346,15 @@ func (t *oidcToken) refresh(ctx context.Context, config OAuth2Config, verifier O
 		logger.Debug(logSender, "", "unable to verify refreshed id token for cookie %q: %v", t.Cookie, err)
 		logger.Debug(logSender, "", "unable to verify refreshed id token for cookie %q: %v", t.Cookie, err)
 		return err
 		return err
 	}
 	}
-	if idToken.Nonce != t.Nonce {
-		logger.Debug(logSender, "", "unable to verify refreshed id token for cookie %q: nonce mismatch", t.Cookie)
+	if idToken.Nonce != "" && idToken.Nonce != t.Nonce {
+		logger.Warn(logSender, "", "unable to verify refreshed id token for cookie %q: nonce mismatch, expected: %q, actual: %q",
+			t.Cookie, t.Nonce, idToken.Nonce)
 		return errors.New("the refreshed token nonce mismatch")
 		return errors.New("the refreshed token nonce mismatch")
 	}
 	}
 	claims := make(map[string]any)
 	claims := make(map[string]any)
 	err = idToken.Claims(&claims)
 	err = idToken.Claims(&claims)
 	if err != nil {
 	if err != nil {
-		logger.Debug(logSender, "", "unable to get refreshed id token claims for cookie %q: %v", t.Cookie, err)
+		logger.Warn(logSender, "", "unable to get refreshed id token claims for cookie %q: %v", t.Cookie, err)
 		return err
 		return err
 	}
 	}
 	sid, ok := claims["sid"].(string)
 	sid, ok := claims["sid"].(string)

+ 4 - 2
internal/httpd/oidc_test.go

@@ -626,7 +626,9 @@ func TestOIDCRefreshToken(t *testing.T) {
 		},
 		},
 	}
 	}
 	verifier = mockOIDCVerifier{
 	verifier = mockOIDCVerifier{
-		token: &oidc.IDToken{},
+		token: &oidc.IDToken{
+			Nonce: xid.New().String(), // nonce is different from the expected one
+		},
 	}
 	}
 	err = token.refresh(context.Background(), &config, &verifier, r)
 	err = token.refresh(context.Background(), &config, &verifier, r)
 	if assert.Error(t, err) {
 	if assert.Error(t, err) {
@@ -634,7 +636,7 @@ func TestOIDCRefreshToken(t *testing.T) {
 	}
 	}
 	verifier = mockOIDCVerifier{
 	verifier = mockOIDCVerifier{
 		token: &oidc.IDToken{
 		token: &oidc.IDToken{
-			Nonce: token.Nonce,
+			Nonce: "", // empty token is fine on refresh but claims are not set
 		},
 		},
 	}
 	}
 	err = token.refresh(context.Background(), &config, &verifier, r)
 	err = token.refresh(context.Background(), &config, &verifier, r)