helpers

package
v0.2.78 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package helpers provides common utility functions used across the mcp-oauth library.

This package contains helper functions for string manipulation, formatting, IP classification, and other shared operations that don't fit into domain-specific packages. These utilities are used internally by multiple packages to avoid code duplication and maintain consistent behavior across the codebase.

Key utilities:

  • SafeTruncate: Safely truncates strings for logging sensitive data
  • ClassifyIP: Classifies IP addresses for SSRF protection (public, private, loopback, etc.)
  • IsLinkLocal: Checks if an IP is link-local (cloud metadata SSRF protection)
  • IsLoopbackHostname: Checks if a hostname represents a loopback address
  • ValidateMetadataPath: Validates paths for security concerns (path traversal, etc.)
  • ValidateClientName: Validates client_name for XSS and log injection prevention

Package helpers provides common utility functions used across the mcp-oauth library.

Package helpers provides common utility functions used across the mcp-oauth library. These utilities handle string manipulation, formatting, and other shared operations that don't fit into domain-specific packages.

Index

Constants

View Source
const MaxClientNameLength = 256

MaxClientNameLength is the maximum allowed length for client_name in runes.

View Source
const MaxMetadataPathLength = 256

MaxMetadataPathLength is the maximum allowed length for custom metadata paths. This prevents DoS attacks through excessively long path registration.

View Source
const MaxPathSegments = 10

MaxPathSegments is the maximum number of path segments (slashes) allowed. This prevents DoS attacks through deeply nested paths.

Variables

This section is empty.

Functions

func FindMatchingAudience added in v0.2.39

func FindMatchingAudience(tokenAudiences, trustedAudiences []string) string

FindMatchingAudience checks if any of the token's audiences match any trusted audience. Returns the first matched token audience value, or empty string if no match. This is the multi-audience version of MatchAudienceSecure for JWT tokens that may have multiple audience claims.

func IsLinkLocal

func IsLinkLocal(ip net.IP) bool

IsLinkLocal checks if an IP address is link-local (unicast or multicast). This includes:

  • IPv4 link-local: 169.254.0.0/16 (also catches cloud metadata 169.254.169.254)
  • IPv6 link-local unicast: fe80::/10
  • IPv6 link-local multicast: ff02::/16

Link-local addresses are a significant security concern in cloud environments as they can access instance metadata services (AWS, GCP, Azure).

func IsLoopbackHostname

func IsLoopbackHostname(hostname string) bool

IsLoopbackHostname checks if a hostname represents a loopback address. This includes the entire 127.0.0.0/8 range (RFC 1122) and IPv6 ::1. Expects hostname without port (as returned by url.URL.Hostname()).

Note: This function does NOT consider 0.0.0.0 as loopback (it's "unspecified").

func IsPrivateOrInternal

func IsPrivateOrInternal(ip net.IP) bool

IsPrivateOrInternal checks if an IP is private, loopback, link-local, or unspecified. This is a convenience function for SSRF protection that returns true for any non-public IP address.

Used by client ID metadata document fetching for comprehensive SSRF protection.

func MatchAudienceSecure added in v0.2.39

func MatchAudienceSecure(tokenAudience string, trustedAudiences []string) string

MatchAudienceSecure checks if a token audience matches any of the trusted audiences. Uses URL normalization for consistent comparison and constant-time comparison for security (defense-in-depth against timing attacks).

Returns the matched trusted audience value, or empty string if no match found. This is used for SSO token forwarding where tokens from trusted upstream services are validated.

Examples:

MatchAudienceSecure("https://example.com", []string{"https://EXAMPLE.COM"}) // Returns "https://EXAMPLE.COM"
MatchAudienceSecure("https://example.com:443/", []string{"https://example.com"}) // Returns "https://example.com"
MatchAudienceSecure("https://other.com", []string{"https://example.com"}) // Returns ""

func NormalizeURL

func NormalizeURL(rawURL string) string

NormalizeURL normalizes a URL for comparison. This is used for RFC 8707 resource identifier and audience comparison, where semantically equivalent URLs should be considered equal.

Normalization includes:

  • Lowercase scheme and host (case-insensitive per RFC 3986)
  • Remove default ports (:443 for https, :80 for http)
  • Remove trailing slashes from path
  • Preserve path case (paths are case-sensitive)

If the input is not a valid URL, it returns the lowercase trimmed input for backwards compatibility with non-URL audience values.

Example:

NormalizeURL("https://EXAMPLE.COM/")       // Returns: "https://example.com"
NormalizeURL("https://example.com:443/")  // Returns: "https://example.com"
NormalizeURL("https://example.com")        // Returns: "https://example.com"
NormalizeURL("https://example.com///")     // Returns: "https://example.com"
NormalizeURL("HTTPS://Example.COM/Path")   // Returns: "https://example.com/Path"
NormalizeURL("client-id")                  // Returns: "client-id" (non-URL)

func PathMatchesPrefix

func PathMatchesPrefix(resourcePath, prefix string) bool

PathMatchesPrefix checks if resourcePath matches or starts with prefix. Handles path boundaries correctly: /mcp/files matches /mcp but not /mc.

This is a pure function used for longest-prefix matching in path configuration lookups. It ensures that path matching respects segment boundaries.

Returns false if either resourcePath or prefix is empty (empty prefix should not match anything in the context of path configuration).

Examples:

PathMatchesPrefix("/mcp/files", "/mcp")    // true - valid prefix match
PathMatchesPrefix("/mcp", "/mcp")          // true - exact match
PathMatchesPrefix("/mcpx", "/mcp")         // false - not a segment boundary
PathMatchesPrefix("/other/mcp", "/mcp")    // false - not a prefix
PathMatchesPrefix("/a", "")                // false - empty prefix

func SafeTruncate

func SafeTruncate(s string, maxLen int) string

SafeTruncate safely truncates a string to maxLen characters without panicking. Returns the original string if it's shorter than maxLen, otherwise returns the first maxLen characters. This prevents index out of bounds errors when logging sensitive data like tokens, where only a prefix should be shown.

If maxLen is negative, it's treated as 0 and returns an empty string.

Example:

SafeTruncate("very-long-token-abc123", 8) // Returns: "very-lon"
SafeTruncate("short", 10)                  // Returns: "short"
SafeTruncate("test", -1)                   // Returns: ""

func ValidateClientName added in v0.2.47

func ValidateClientName(name string) error

ValidateClientName validates the client_name field to prevent potential stored XSS, script injection, and log injection attacks. This is a defense-in-depth measure - while client_name is typically only used in JSON responses (which escape HTML), validation prevents issues if the value is ever displayed in various contexts (admin dashboards, log viewers, audit reports, markdown renderers).

Validation rules:

  • Must not contain HTML-like characters (< or >)
  • Must not contain quote characters (' " `) that enable script/template injection
  • Must not exceed 256 characters (runes, not bytes)
  • Must contain only printable characters (no control characters)
  • Must not contain newlines (prevents log line splitting attacks)

Returns nil if the name is valid, or an error describing the validation failure.

func ValidateMetadataPath

func ValidateMetadataPath(path string) error

ValidateMetadataPath validates a metadata path for security concerns. This is used by both the HTTP handler (for runtime requests) and config validation (for startup configuration).

Security checks performed:

  • Path traversal sequences (..)
  • Null bytes (can cause issues in some HTTP implementations)
  • Excessive path length (DoS prevention)
  • Excessive path segments (DoS prevention)

Returns nil if the path is valid, otherwise returns an error describing the issue.

Types

type IPClassification

type IPClassification int

IPClassification represents the security classification of an IP address. This is used for SSRF protection in redirect URI validation and client ID metadata fetching.

const (
	// IPClassificationPublic indicates a publicly routable IP address.
	IPClassificationPublic IPClassification = iota
	// IPClassificationLoopback indicates a loopback address (127.0.0.0/8, ::1).
	IPClassificationLoopback
	// IPClassificationPrivate indicates a private/internal address (RFC 1918, ULA).
	IPClassificationPrivate
	// IPClassificationLinkLocal indicates a link-local address (169.254.x.x, fe80::/10).
	IPClassificationLinkLocal
	// IPClassificationUnspecified indicates an unspecified address (0.0.0.0, ::).
	IPClassificationUnspecified
)

func ClassifyIP

func ClassifyIP(ip net.IP) IPClassification

ClassifyIP returns the security classification of an IP address. This is the single source of truth for IP classification used across the library for SSRF protection in redirect URI validation and client metadata fetching.

Classifications:

  • Unspecified: 0.0.0.0, :: (always dangerous, undefined behavior)
  • Loopback: 127.0.0.0/8, ::1 (allowed for native apps per RFC 8252)
  • LinkLocal: 169.254.0.0/16, fe80::/10 (cloud metadata SSRF risk)
  • Private: RFC 1918 (10/8, 172.16/12, 192.168/16), fc00::/7 (SSRF to internal networks)
  • Public: All other addresses (generally safe)

func (IPClassification) String

func (c IPClassification) String() string

String returns a human-readable name for the IP classification.

type PathValidationError

type PathValidationError struct {
	Path   string
	Reason string
}

PathValidationError represents a path validation failure.

func (*PathValidationError) Error

func (e *PathValidationError) Error() string

Error implements the error interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL