mcp: add optional issuer validator for pre-registered client validation (SEP-2352) (#946)
Fixes #978
This commit is contained in:
parent
189a85ad92
commit
dfb45f1e11
3 changed files with 190 additions and 5 deletions
|
|
@ -12,7 +12,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/authutil"
|
||||
)
|
||||
|
||||
// AuthServerMeta represents the metadata for an OAuth 2.0 authorization server,
|
||||
|
|
@ -153,8 +154,7 @@ func GetAuthServerMeta(ctx context.Context, metadataURL, issuer string, c *http.
|
|||
}
|
||||
return nil, fmt.Errorf("%v", err) // Do not expose error types.
|
||||
}
|
||||
if strings.TrimRight(asm.Issuer, "/") != strings.TrimRight(issuer, "/") {
|
||||
// Validate the Issuer field (see RFC 8414, section 3.3).
|
||||
if !authutil.IssuersEqual(asm.Issuer, issuer) {
|
||||
return nil, fmt.Errorf("metadata issuer %q does not match issuer URL %q", asm.Issuer, issuer)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,15 @@ type ClientCredentials struct {
|
|||
// This is the most common authentication method for confidential clients.
|
||||
// OPTIONAL. If not provided, the client is treated as a public client.
|
||||
ClientSecretAuth *ClientSecretAuth
|
||||
|
||||
// Issuer is the issuer identifier of the authorization server these
|
||||
// credentials are registered with. Pre-registered credentials are bound
|
||||
// to a specific authorization server; when set, an error is returned if
|
||||
// the discovered authorization server does not match, per SEP-2352.
|
||||
// The comparison ignores a single trailing slash, matching the
|
||||
// tolerance applied during RFC 8414 Section 3.3 metadata validation.
|
||||
// OPTIONAL.
|
||||
Issuer string
|
||||
}
|
||||
|
||||
// ClientSecretAuth holds client secret authentication credentials.
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ func TestClientCredentials_ValidateCoversAllAuthFields(t *testing.T) {
|
|||
var pointerFields int
|
||||
for i := range typ.NumField() {
|
||||
f := typ.Field(i)
|
||||
if f.Name == "ClientID" {
|
||||
if f.Name == "ClientID" || f.Name == "Issuer" {
|
||||
continue
|
||||
}
|
||||
if f.Type.Kind() != reflect.Ptr {
|
||||
|
|
|
|||
Loading…
Reference in a new issue