mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-17 04:37:48 +00:00
- fail-on-old regression tests for every shipped fix (R-rounds) - fuzz targets (parseJWT, bearer), concurrency-stress, shuffle-flake guards - coverage-closing contract tests (health-check backend, TLS-posture reuse) - r154 ID-token fixture built from parts to avoid false-positive secret scan
63 lines
2.3 KiB
Go
63 lines
2.3 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestR171_IntrospectionEndsBasicKeform tests that the RFC 7662 introspection
|
|
// path (introtoken in token_introspection.go) authenticates the client with
|
|
// the SAME RFC 6749 §2.3.1 basic-auth encoding as the token and revocation
|
|
// endpoints (setOAuthBasicAuth): client_id and client_secret are
|
|
// form-urlencoded individually before the base64 step. Previously it used
|
|
// http.Request.SetBasicAuth (which base64s client_id:client_secret raw with
|
|
// no escaping), so for credentials containing reserved characters (":", "+",
|
|
// "@", "/", "=") the three outbound provider calls sent different wire
|
|
// credentials and an RFC 6749-strict provider rejected introspection with
|
|
// invalid_client while token exchange succeeded.
|
|
func TestR171_IntrospectionUsesOAuthBasicAuthNotRawSetBasicAuth(t *testing.T) {
|
|
var capturedAuth string
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
capturedAuth = r.Header.Get("Authorization")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
// active=false keeps this free of introspection-cache state.
|
|
_ = json.NewEncoder(w).Encode(map[string]interface{}{"active": false, "token_type": "Bearer"})
|
|
}))
|
|
defer server.Close()
|
|
|
|
const (
|
|
clientID = "weird:id+1"
|
|
clientSecret = "p@ss/word=&" //nolint:gosec // test fixture
|
|
)
|
|
|
|
oidc := &TraefikOidc{
|
|
clientID: clientID,
|
|
clientSecret: clientSecret,
|
|
clientAuthMethod: "client_secret_basic",
|
|
httpClient: server.Client(),
|
|
logger: GetSingletonNoOpLogger(),
|
|
}
|
|
oidc.introspectionURL = server.URL
|
|
oidc.tokenURL = "https://idp.example.com/token"
|
|
|
|
_, err := oidc.introspectToken("opaque-token")
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, strings.HasPrefix(capturedAuth, "Basic "), "got %q", capturedAuth)
|
|
raw, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(capturedAuth, "Basic "))
|
|
require.NoError(t, err)
|
|
|
|
wantUser := url.QueryEscape(clientID)
|
|
wantPass := url.QueryEscape(clientSecret)
|
|
assert.Equal(t, wantUser+":"+wantPass, string(raw),
|
|
"introspection must form-urlencode client_id and client_secret before base64, matching the token/revocation endpoints")
|
|
}
|