Skip to content

Commit cab4c0b

Browse files
RahulHereRahulHere
authored andcommitted
Implement Validation Options (#130)
- Added constructor with default values to validation options struct - Enhanced scope validation with whitespace trimming - Enhanced audience validation with whitespace handling - Added clock skew validation with range checking - Implemented helper methods for checking validation requirements - Made validation options NULL-safe throughout the code - Added warning for unusually large clock skew values - Improved error context in option creation failures - Used helper methods in token validation for clarity - Ensured proper defaults when options are NULL
1 parent b4a1f8b commit cab4c0b

File tree

1 file changed

+73
-8
lines changed

1 file changed

+73
-8
lines changed

src/c_api/mcp_c_auth_api.cc

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,21 @@ struct mcp_auth_client {
10091009
struct mcp_auth_validation_options {
10101010
std::string scopes;
10111011
std::string audience;
1012-
int64_t clock_skew = 60;
1012+
int64_t clock_skew = 60; // Default: 60 seconds
1013+
1014+
// Constructor with defaults
1015+
mcp_auth_validation_options()
1016+
: clock_skew(60) {} // Ensure default is set
1017+
1018+
// Helper to check if options require scope validation
1019+
bool requires_scope_validation() const {
1020+
return !scopes.empty();
1021+
}
1022+
1023+
// Helper to check if options require audience validation
1024+
bool requires_audience_validation() const {
1025+
return !audience.empty();
1026+
}
10131027
};
10141028

10151029
// Store error in client structure with context (moved after struct definition)
@@ -1537,9 +1551,13 @@ mcp_auth_error_t mcp_auth_validation_options_create(
15371551

15381552
try {
15391553
*options = new mcp_auth_validation_options();
1554+
// Options are already initialized with defaults via constructor
1555+
// clock_skew = 60, scopes = "", audience = ""
15401556
return MCP_AUTH_SUCCESS;
15411557
} catch (const std::exception& e) {
1542-
set_error(MCP_AUTH_ERROR_OUT_OF_MEMORY, e.what());
1558+
set_error_with_context(MCP_AUTH_ERROR_OUT_OF_MEMORY,
1559+
"Failed to create validation options",
1560+
std::string("Exception: ") + e.what());
15431561
return MCP_AUTH_ERROR_OUT_OF_MEMORY;
15441562
}
15451563
}
@@ -1586,7 +1604,22 @@ mcp_auth_error_t mcp_auth_validation_options_set_scopes(
15861604
}
15871605

15881606
clear_error();
1589-
options->scopes = scopes ? scopes : "";
1607+
1608+
// Validate and normalize scope string
1609+
if (scopes) {
1610+
// Trim whitespace from scopes
1611+
std::string scope_str(scopes);
1612+
size_t first = scope_str.find_first_not_of(' ');
1613+
if (first != std::string::npos) {
1614+
size_t last = scope_str.find_last_not_of(' ');
1615+
options->scopes = scope_str.substr(first, (last - first + 1));
1616+
} else {
1617+
options->scopes = ""; // All whitespace
1618+
}
1619+
} else {
1620+
options->scopes = ""; // Clear scopes if NULL
1621+
}
1622+
15901623
return MCP_AUTH_SUCCESS;
15911624
}
15921625

@@ -1605,7 +1638,25 @@ mcp_auth_error_t mcp_auth_validation_options_set_audience(
16051638
}
16061639

16071640
clear_error();
1608-
options->audience = audience ? audience : "";
1641+
1642+
// Validate and store audience
1643+
if (audience) {
1644+
// Trim whitespace from audience
1645+
std::string aud_str(audience);
1646+
size_t first = aud_str.find_first_not_of(' ');
1647+
if (first != std::string::npos) {
1648+
size_t last = aud_str.find_last_not_of(' ');
1649+
options->audience = aud_str.substr(first, (last - first + 1));
1650+
} else {
1651+
options->audience = ""; // All whitespace
1652+
}
1653+
1654+
// Optionally validate audience format (e.g., URL or identifier)
1655+
// For now, accept any non-empty string
1656+
} else {
1657+
options->audience = ""; // Clear audience if NULL
1658+
}
1659+
16091660
return MCP_AUTH_SUCCESS;
16101661
}
16111662

@@ -1624,6 +1675,20 @@ mcp_auth_error_t mcp_auth_validation_options_set_clock_skew(
16241675
}
16251676

16261677
clear_error();
1678+
1679+
// Validate clock skew range
1680+
if (seconds < 0) {
1681+
set_error_with_context(MCP_AUTH_ERROR_INVALID_CONFIG,
1682+
"Invalid clock skew",
1683+
"Clock skew must be non-negative: " + std::to_string(seconds));
1684+
return MCP_AUTH_ERROR_INVALID_CONFIG;
1685+
}
1686+
1687+
// Warn if clock skew is unusually large (> 5 minutes)
1688+
if (seconds > 300) {
1689+
fprintf(stderr, "Warning: Large clock skew configured: %lld seconds\n", (long long)seconds);
1690+
}
1691+
16271692
options->clock_skew = seconds;
16281693
return MCP_AUTH_SUCCESS;
16291694
}
@@ -1800,8 +1865,8 @@ mcp_auth_error_t mcp_auth_validate_token(
18001865
}
18011866
}
18021867

1803-
// Validate audience if specified
1804-
if (options && !options->audience.empty()) {
1868+
// Validate audience if specified (using helper method for clarity)
1869+
if (options && options->requires_audience_validation()) {
18051870
if (payload_data.audience.empty()) {
18061871
set_error(MCP_AUTH_ERROR_INVALID_AUDIENCE, "JWT has no audience claim");
18071872
result->error_code = MCP_AUTH_ERROR_INVALID_AUDIENCE;
@@ -1820,8 +1885,8 @@ mcp_auth_error_t mcp_auth_validate_token(
18201885
}
18211886
}
18221887

1823-
// Validate scopes if required
1824-
if (options && !options->scopes.empty()) {
1888+
// Validate scopes if required (using helper method for clarity)
1889+
if (options && options->requires_scope_validation()) {
18251890
if (payload_data.scopes.empty()) {
18261891
set_error(MCP_AUTH_ERROR_INSUFFICIENT_SCOPE, "JWT has no scope claim");
18271892
result->error_code = MCP_AUTH_ERROR_INSUFFICIENT_SCOPE;

0 commit comments

Comments
 (0)