Skip to content

Commit 3320ecb

Browse files
refactors .well-known/ts.jwks.json -> .well-known/trusted-server.json
1 parent 68ebba4 commit 3320ecb

File tree

4 files changed

+147
-6
lines changed

4 files changed

+147
-6
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Discovery endpoint for trusted-server.
2+
//!
3+
//! This module provides a standardized discovery mechanism similar to the IAB's
4+
//! Data Subject Rights framework. The `.well-known/trusted-server.json` endpoint
5+
//! allows partners to discover JWKS keys for signature verification.
6+
7+
use serde::Serialize;
8+
9+
/// Main discovery document returned by `.well-known/trusted-server.json`
10+
#[derive(Debug, Serialize)]
11+
pub struct TrustedServerDiscovery {
12+
/// Version of the discovery document format
13+
pub version: String,
14+
15+
/// JSON Web Key Set containing public keys for signature verification
16+
pub jwks: serde_json::Value,
17+
}
18+
19+
impl TrustedServerDiscovery {
20+
/// Creates a new discovery document with the given JWKS
21+
pub fn new(jwks_value: serde_json::Value) -> Self {
22+
Self {
23+
version: "1.0".to_string(),
24+
jwks: jwks_value,
25+
}
26+
}
27+
}
28+
29+
#[cfg(test)]
30+
mod tests {
31+
use super::*;
32+
use serde_json::json;
33+
34+
#[test]
35+
fn test_discovery_document_structure() {
36+
let jwks = json!({
37+
"keys": [
38+
{
39+
"kty": "OKP",
40+
"crv": "Ed25519",
41+
"x": "test_key",
42+
"kid": "test-kid"
43+
}
44+
]
45+
});
46+
47+
let discovery = TrustedServerDiscovery::new(jwks);
48+
49+
assert_eq!(discovery.version, "1.0");
50+
assert!(discovery.jwks.is_object());
51+
}
52+
53+
#[test]
54+
fn test_discovery_document_serialization() {
55+
let jwks = json!({
56+
"keys": []
57+
});
58+
59+
let discovery = TrustedServerDiscovery::new(jwks);
60+
let serialized = serde_json::to_string(&discovery).unwrap();
61+
62+
// Verify it's valid JSON
63+
let parsed: serde_json::Value = serde_json::from_str(&serialized).unwrap();
64+
65+
assert_eq!(parsed["version"], "1.0");
66+
assert!(parsed.get("jwks").is_some());
67+
assert!(parsed.get("endpoints").is_none());
68+
}
69+
70+
#[test]
71+
fn test_discovery_includes_jwks() {
72+
let jwks = json!({
73+
"keys": [
74+
{
75+
"kty": "OKP",
76+
"kid": "test-key"
77+
}
78+
]
79+
});
80+
81+
let discovery = TrustedServerDiscovery::new(jwks);
82+
let serialized = serde_json::to_string(&discovery).unwrap();
83+
let parsed: serde_json::Value = serde_json::from_str(&serialized).unwrap();
84+
85+
assert!(parsed["jwks"]["keys"].is_array());
86+
assert_eq!(parsed["jwks"]["keys"][0]["kid"], "test-key");
87+
}
88+
}

crates/common/src/request_signing/endpoints.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,43 @@ use fastly::{Request, Response};
88
use serde::{Deserialize, Serialize};
99

1010
use crate::error::TrustedServerError;
11+
use crate::request_signing::discovery::TrustedServerDiscovery;
1112
use crate::request_signing::rotation::KeyRotationManager;
1213
use crate::request_signing::signing;
1314
use crate::settings::Settings;
1415

15-
/// Retrieves and returns active jwks public keys.
16-
pub fn handle_jwks_endpoint(
16+
/// Retrieves and returns the trusted-server discovery document.
17+
///
18+
/// This endpoint provides a standardized discovery mechanism following the IAB
19+
/// Data Subject Rights framework pattern. It returns JWKS keys and API endpoints
20+
/// in a single discoverable location.
21+
pub fn handle_trusted_server_discovery(
1722
_settings: &Settings,
1823
_req: Request,
1924
) -> Result<Response, Report<TrustedServerError>> {
25+
// Get JWKS
2026
let jwks_json = crate::request_signing::jwks::get_active_jwks().change_context(
2127
TrustedServerError::Configuration {
2228
message: "Failed to retrieve JWKS".into(),
2329
},
2430
)?;
2531

32+
let jwks_value: serde_json::Value =
33+
serde_json::from_str(&jwks_json).change_context(TrustedServerError::Configuration {
34+
message: "Failed to parse JWKS JSON".into(),
35+
})?;
36+
37+
let discovery = TrustedServerDiscovery::new(jwks_value);
38+
39+
let json = serde_json::to_string_pretty(&discovery).change_context(
40+
TrustedServerError::Configuration {
41+
message: "Failed to serialize discovery document".into(),
42+
},
43+
)?;
44+
2645
Ok(Response::from_status(200)
2746
.with_content_type(fastly::mime::APPLICATION_JSON)
28-
.with_body_text_plain(&jwks_json))
47+
.with_body_text_plain(&json))
2948
}
3049

3150
#[derive(Debug, Deserialize, Serialize)]
@@ -514,4 +533,33 @@ mod tests {
514533
assert_eq!(req.kid, "old-key");
515534
assert!(req.delete);
516535
}
536+
537+
#[test]
538+
fn test_handle_trusted_server_discovery() {
539+
let settings = crate::test_support::tests::create_test_settings();
540+
let req = Request::new(
541+
Method::GET,
542+
"https://test.com/.well-known/trusted-server.json",
543+
);
544+
545+
let result = handle_trusted_server_discovery(&settings, req);
546+
match result {
547+
Ok(mut resp) => {
548+
assert_eq!(resp.get_status(), StatusCode::OK);
549+
let body = resp.take_body_str();
550+
551+
// Parse the discovery document
552+
let discovery: serde_json::Value = serde_json::from_str(&body).unwrap();
553+
554+
// Verify structure - only version and jwks
555+
assert_eq!(discovery["version"], "1.0");
556+
assert!(discovery["jwks"].is_object());
557+
558+
// Verify no extra fields
559+
assert!(discovery.get("endpoints").is_none());
560+
assert!(discovery.get("capabilities").is_none());
561+
}
562+
Err(e) => println!("Expected error in test environment: {}", e),
563+
}
564+
}
517565
}

crates/common/src/request_signing/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
//! This module provides cryptographic signing capabilities using Ed25519 keys,
44
//! including JWKS management, key rotation, and signature verification.
55
6+
pub mod discovery;
67
pub mod endpoints;
78
pub mod jwks;
89
pub mod rotation;
910
pub mod signing;
1011

12+
pub use discovery::*;
1113
pub use endpoints::*;
1214
pub use jwks::*;
1315
pub use rotation::*;

crates/fastly/src/main.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use trusted_server_common::proxy::{
1212
};
1313
use trusted_server_common::publisher::{handle_publisher_request, handle_tsjs_dynamic};
1414
use trusted_server_common::request_signing::{
15-
handle_deactivate_key, handle_jwks_endpoint, handle_rotate_key, handle_verify_signature,
15+
handle_deactivate_key, handle_rotate_key, handle_trusted_server_discovery,
16+
handle_verify_signature,
1617
};
1718
use trusted_server_common::settings::Settings;
1819
use trusted_server_common::settings_data::get_settings;
@@ -62,8 +63,10 @@ async fn route_request(
6263
handle_tsjs_dynamic(&settings, req)
6364
}
6465

65-
// JWKS endpoint for public key distribution
66-
(Method::GET, "/.well-known/ts.jwks.json") => handle_jwks_endpoint(&settings, req),
66+
// Discovery endpoint for trusted-server capabilities and JWKS
67+
(Method::GET, "/.well-known/trusted-server.json") => {
68+
handle_trusted_server_discovery(&settings, req)
69+
}
6770

6871
// Signature verification endpoint
6972
(Method::POST, "/verify-signature") => handle_verify_signature(&settings, req),

0 commit comments

Comments
 (0)