mcp connection
This commit is contained in:
107
go-api/internal/oauth/pkce_test.go
Normal file
107
go-api/internal/oauth/pkce_test.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// The RFC 7636 appendix B worked example. Using the spec's own vector rather
|
||||
// than a value this implementation produced means the test would catch an
|
||||
// encoding mistake that is self-consistent — base64 standard instead of
|
||||
// base64url, say, or padded instead of raw — which a round-trip test could not.
|
||||
const (
|
||||
specVerifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
|
||||
specChallenge = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
|
||||
)
|
||||
|
||||
func TestChallengeForMatchesTheRFCVector(t *testing.T) {
|
||||
if got := ChallengeFor(specVerifier); got != specChallenge {
|
||||
t.Errorf("ChallengeFor(RFC 7636 verifier) = %q, want %q", got, specChallenge)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyChallengeAcceptsTheCorrectVerifier(t *testing.T) {
|
||||
if err := VerifyChallenge(specVerifier, specChallenge, MethodS256); err != nil {
|
||||
t.Errorf("the RFC's own verifier was rejected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyChallengeRejectsAWrongVerifier(t *testing.T) {
|
||||
// Same length and character set, one character different. A comparison
|
||||
// that was accidentally checking length or prefix would let this through.
|
||||
wrong := "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXX"
|
||||
err := VerifyChallenge(wrong, specChallenge, MethodS256)
|
||||
if !errors.Is(err, ErrVerifierMismatch) {
|
||||
t.Errorf("err = %v, want ErrVerifierMismatch", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyChallengeRejectsAMissingVerifier(t *testing.T) {
|
||||
if err := VerifyChallenge("", specChallenge, MethodS256); !errors.Is(err, ErrMalformedVerifier) {
|
||||
t.Errorf("err = %v, want ErrMalformedVerifier", err)
|
||||
}
|
||||
}
|
||||
|
||||
// `plain` must be refused wherever it appears. It is legal in RFC 7636 and
|
||||
// forbidden by OAuth 2.1 for public clients, because the challenge IS the
|
||||
// verifier and anyone who stole one stole both.
|
||||
func TestPlainMethodIsRejected(t *testing.T) {
|
||||
for _, method := range []string{"plain", "PLAIN", "", "s256", "S512"} {
|
||||
t.Run("method="+method, func(t *testing.T) {
|
||||
if err := ValidateChallenge(specChallenge, method); !errors.Is(err, ErrUnsupportedChallengeMethod) {
|
||||
t.Errorf("ValidateChallenge: err = %v, want ErrUnsupportedChallengeMethod", err)
|
||||
}
|
||||
if err := VerifyChallenge(specVerifier, specChallenge, method); !errors.Is(err, ErrUnsupportedChallengeMethod) {
|
||||
t.Errorf("VerifyChallenge: err = %v, want ErrUnsupportedChallengeMethod", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMalformedChallengeIsRejected(t *testing.T) {
|
||||
for name, challenge := range map[string]string{
|
||||
"empty": "",
|
||||
"too short": "abc",
|
||||
"too long": strings.Repeat("a", 44),
|
||||
"padded base64": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM=",
|
||||
"standard base64": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw+cM",
|
||||
"illegal char": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw!cM",
|
||||
"whitespace": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw cM",
|
||||
"newline injected": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw\ncM",
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if err := ValidateChallenge(challenge, MethodS256); !errors.Is(err, ErrMalformedChallenge) {
|
||||
t.Errorf("err = %v, want ErrMalformedChallenge", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 7636 section 4.1 constrains the verifier to 43–128 unreserved characters.
|
||||
// A verifier outside that range is malformed regardless of what it hashes to.
|
||||
func TestMalformedVerifierIsRejected(t *testing.T) {
|
||||
for name, verifier := range map[string]string{
|
||||
"too short (42)": strings.Repeat("a", 42),
|
||||
"too long (129)": strings.Repeat("a", 129),
|
||||
"illegal char": strings.Repeat("a", 42) + "!",
|
||||
"whitespace": strings.Repeat("a", 42) + " ",
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if err := VerifyChallenge(verifier, specChallenge, MethodS256); !errors.Is(err, ErrMalformedVerifier) {
|
||||
t.Errorf("err = %v, want ErrMalformedVerifier", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A verifier at each end of the legal range must be accepted, or clients
|
||||
// generating the maximum length would fail against this server.
|
||||
func TestVerifierBoundariesAreAccepted(t *testing.T) {
|
||||
for _, length := range []int{43, 128} {
|
||||
verifier := strings.Repeat("a", length)
|
||||
if err := VerifyChallenge(verifier, ChallengeFor(verifier), MethodS256); err != nil {
|
||||
t.Errorf("a %d-character verifier was rejected: %v", length, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user