diff --git a/aggregator/src/bin/janus_cli.rs b/aggregator/src/bin/janus_cli.rs index 7e114e7e9..322b0b344 100644 --- a/aggregator/src/bin/janus_cli.rs +++ b/aggregator/src/bin/janus_cli.rs @@ -730,9 +730,9 @@ mod tests { aggregator_auth_token: type: Bearer token: Y29sbGVjdG9yLWFiZjU0MDhlMmIxNjAxODMxNjI1YWYzOTU5MTA2NDU4 - collector_auth_token: + collector_auth_token_hash: type: Bearer - token: Y29sbGVjdG9yLWFiZjU0MDhlMmIxNjAxODMxNjI1YWYzOTU5MTA2NDU4 + hash: MJOoBO_ysLEuG_lv2C37eEOf1Ngetsr-Ers0ZYj4vdQ hpke_keys: [] - peer_aggregator_endpoint: https://leader query_type: TimeInterval @@ -801,8 +801,8 @@ mod tests { for task in &got_tasks { match task.role() { - Role::Leader => assert!(task.collector_auth_token().is_some()), - Role::Helper => assert!(task.collector_auth_token().is_none()), + Role::Leader => assert!(task.collector_auth_token_hash().is_some()), + Role::Helper => assert!(task.collector_auth_token_hash().is_none()), role => panic!("unexpected role {role}"), } } diff --git a/aggregator_api/src/models.rs b/aggregator_api/src/models.rs index 9047ec454..13030d37e 100644 --- a/aggregator_api/src/models.rs +++ b/aggregator_api/src/models.rs @@ -4,7 +4,10 @@ use janus_aggregator_core::{ task::{AggregatorTask, QueryType}, taskprov::{PeerAggregator, VerifyKeyInit}, }; -use janus_core::{auth_tokens::AuthenticationToken, vdaf::VdafInstance}; +use janus_core::{ + auth_tokens::{AuthenticationToken, AuthenticationTokenHash}, + vdaf::VdafInstance, +}; use janus_messages::{ query_type::Code as SupportedQueryType, Duration, HpkeAeadId, HpkeConfig, HpkeKdfId, HpkeKemId, Role, TaskId, Time, @@ -28,6 +31,7 @@ pub(crate) struct AggregatorApiConfig { pub role: AggregatorRole, pub vdafs: Vec, pub query_types: Vec, + pub features: &'static [&'static str], } #[allow(clippy::enum_variant_names)] @@ -76,6 +80,10 @@ pub(crate) struct PostTaskReq { /// If this aggregator is the leader, this is the token to use to authenticate requests to /// the helper. If this aggregator is the helper, the value is `None`. pub(crate) aggregator_auth_token: Option, + /// If this aggregator is the leader, this is the token hash used to authenticate collection + /// sub-protocol requests received from the helper. If this aggregator is the helper, the value + /// is `None`. + pub(crate) collector_auth_token_hash: Option, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -112,11 +120,6 @@ pub(crate) struct TaskResp { /// initial response to a task creation request and only when the role is helper. Subsequent /// `TaskResp`s obtained from `GET /tasks/:task_id` will not contain the authentication token. pub(crate) aggregator_auth_token: Option, - /// The authentication token used by the task's Collector to authenticate to the Leader. - /// `Some` if `role` is Leader, `None` otherwise. - // TODO(#1509) This field will have to change as Janus leaders will only store a salted hash - // of collector auth tokens. - pub(crate) collector_auth_token: Option, /// HPKE configuration used by the collector to decrypt aggregate shares. pub(crate) collector_hpke_config: HpkeConfig, /// HPKE configuration(s) used by this aggregator to decrypt report shares. @@ -148,7 +151,6 @@ impl TryFrom<&AggregatorTask> for TaskResp { time_precision: *task.time_precision(), tolerable_clock_skew: *task.tolerable_clock_skew(), aggregator_auth_token: None, - collector_auth_token: task.collector_auth_token().cloned(), collector_hpke_config: task .collector_hpke_config() .ok_or("collector_hpke_config is required")? diff --git a/aggregator_api/src/routes.rs b/aggregator_api/src/routes.rs index 55f97a07e..77a2f4daa 100644 --- a/aggregator_api/src/routes.rs +++ b/aggregator_api/src/routes.rs @@ -48,6 +48,8 @@ pub(super) async fn get_config( SupportedQueryType::TimeInterval, SupportedQueryType::FixedSize, ], + // Unconditionally indicate to divviup-api that we support collector auth token hashes + features: &["token-hash"], }) } @@ -113,11 +115,17 @@ pub(super) async fn post_task( .to_string(), ) })?; + let collector_auth_token_hash = req.collector_auth_token_hash.ok_or_else(|| { + Error::BadRequest( + "aggregator acting in leader role must be provided a collector auth token" + .to_string(), + ) + })?; ( None, AggregatorTaskParameters::Leader { aggregator_auth_token, - collector_auth_token: random(), + collector_auth_token_hash, collector_hpke_config: req.collector_hpke_config, }, ) diff --git a/aggregator_api/src/tests.rs b/aggregator_api/src/tests.rs index a0da39b97..f10efa359 100644 --- a/aggregator_api/src/tests.rs +++ b/aggregator_api/src/tests.rs @@ -24,7 +24,7 @@ use janus_aggregator_core::{ SecretBytes, }; use janus_core::{ - auth_tokens::AuthenticationToken, + auth_tokens::{AuthenticationToken, AuthenticationTokenHash}, hpke::{ generate_hpke_config_and_private_key, test_util::{ @@ -86,7 +86,8 @@ async fn get_config() { concat!( r#"{"protocol":"DAP-07","dap_url":"https://dap.url/","role":"Either","vdafs":"#, r#"["Prio3Count","Prio3Sum","Prio3Histogram","Prio3CountVec","Prio3SumVec"],"#, - r#""query_types":["TimeInterval","FixedSize"]}"# + r#""query_types":["TimeInterval","FixedSize"],"#, + r#""features":["token-hash"]}"#, ) ); } @@ -214,6 +215,7 @@ async fn post_task_bad_role() { .config() .clone(), aggregator_auth_token: Some(aggregator_auth_token), + collector_auth_token_hash: Some(AuthenticationTokenHash::from(&random())), }; assert_response!( post("/tasks") @@ -255,6 +257,7 @@ async fn post_task_unauthorized() { .config() .clone(), aggregator_auth_token: Some(aggregator_auth_token), + collector_auth_token_hash: Some(AuthenticationTokenHash::from(&random())), }; assert_response!( post("/tasks") @@ -297,6 +300,7 @@ async fn post_task_helper_no_optional_fields() { .config() .clone(), aggregator_auth_token: None, + collector_auth_token_hash: None, }; let mut conn = post("/tasks") .with_request_body(serde_json::to_vec(&req).unwrap()) @@ -345,7 +349,7 @@ async fn post_task_helper_no_optional_fields() { assert_eq!(req.min_batch_size, got_task.min_batch_size()); assert_eq!(&req.time_precision, got_task.time_precision()); assert!(got_task.aggregator_auth_token().is_none()); - assert!(got_task.collector_auth_token().is_none()); + assert!(got_task.collector_auth_token_hash().is_none()); assert_eq!( &req.collector_hpke_config, got_task.collector_hpke_config().unwrap() @@ -386,6 +390,7 @@ async fn post_task_helper_with_aggregator_auth_token() { .config() .clone(), aggregator_auth_token: Some(aggregator_auth_token), + collector_auth_token_hash: None, }; assert_response!( post("/tasks") @@ -429,6 +434,8 @@ async fn post_task_idempotence() { .config() .clone(), aggregator_auth_token: Some(aggregator_auth_token.clone()), + + collector_auth_token_hash: Some(AuthenticationTokenHash::from(&random())), }; let post_task = || async { @@ -488,7 +495,7 @@ async fn post_task_leader_all_optional_fields() { let vdaf_verify_key = SecretBytes::new(thread_rng().sample_iter(Standard).take(16).collect()); let aggregator_auth_token = AuthenticationToken::DapAuth(random()); - + let collector_auth_token_hash = AuthenticationTokenHash::from(&random()); // Verify: posting a task creates a new task which matches the request. let req = PostTaskReq { peer_aggregator_endpoint: "http://aggregator.endpoint".try_into().unwrap(), @@ -510,6 +517,7 @@ async fn post_task_leader_all_optional_fields() { .config() .clone(), aggregator_auth_token: Some(aggregator_auth_token.clone()), + collector_auth_token_hash: Some(collector_auth_token_hash.clone()), }; let mut conn = post("/tasks") .with_request_body(serde_json::to_vec(&req).unwrap()) @@ -559,7 +567,10 @@ async fn post_task_leader_all_optional_fields() { aggregator_auth_token.as_ref(), got_task.aggregator_auth_token().unwrap().as_ref() ); - assert!(got_task.collector_auth_token().is_some()); + assert_eq!( + got_task.collector_auth_token_hash().unwrap(), + &collector_auth_token_hash + ); // ...and the response. assert_eq!(got_task_resp, TaskResp::try_from(&got_task).unwrap()); @@ -594,6 +605,7 @@ async fn post_task_leader_no_aggregator_auth_token() { .config() .clone(), aggregator_auth_token: None, + collector_auth_token_hash: Some(AuthenticationTokenHash::from(&random())), }; assert_response!( @@ -1555,11 +1567,12 @@ fn post_task_req_serialization() { HpkePublicKey::from([0u8; 32].to_vec()), ), aggregator_auth_token: None, + collector_auth_token_hash: None, }, &[ Token::Struct { name: "PostTaskReq", - len: 11, + len: 12, }, Token::Str("peer_aggregator_endpoint"), Token::Str("https://example.com/"), @@ -1631,6 +1644,8 @@ fn post_task_req_serialization() { Token::StructEnd, Token::Str("aggregator_auth_token"), Token::None, + Token::Str("collector_auth_token_hash"), + Token::None, Token::StructEnd, ], ); @@ -1663,11 +1678,14 @@ fn post_task_req_serialization() { aggregator_auth_token: Some( AuthenticationToken::new_dap_auth_token_from_string("ZW5jb2RlZA").unwrap(), ), + collector_auth_token_hash: Some(AuthenticationTokenHash::from( + &AuthenticationToken::new_dap_auth_token_from_string("ZW5jb2RlZA").unwrap(), + )), }, &[ Token::Struct { name: "PostTaskReq", - len: 11, + len: 12, }, Token::Str("peer_aggregator_endpoint"), Token::Str("https://example.com/"), @@ -1753,6 +1771,20 @@ fn post_task_req_serialization() { Token::Str("token"), Token::Str("ZW5jb2RlZA"), Token::StructEnd, + Token::Str("collector_auth_token_hash"), + Token::Some, + Token::Struct { + name: "AuthenticationTokenHash", + len: 2, + }, + Token::Str("type"), + Token::UnitVariant { + name: "AuthenticationTokenHash", + variant: "DapAuth", + }, + Token::Str("hash"), + Token::Str("hT_ixzv_X1CmJmHGT7jYSEBbdB-CN9H8WxAvjgv4rms"), + Token::StructEnd, Token::StructEnd, ], ); @@ -1793,10 +1825,10 @@ fn task_resp_serialization() { "Y29sbGVjdG9yLWFiY2RlZjAw", ) .unwrap(), - collector_auth_token: AuthenticationToken::new_dap_auth_token_from_string( - "Y29sbGVjdG9yLWFiY2RlZjAw", - ) - .unwrap(), + collector_auth_token_hash: AuthenticationTokenHash::from( + &AuthenticationToken::new_dap_auth_token_from_string("Y29sbGVjdG9yLWFiY2RlZjAw") + .unwrap(), + ), collector_hpke_config: HpkeConfig::new( HpkeConfigId::from(7), HpkeKemId::X25519HkdfSha256, @@ -1812,7 +1844,7 @@ fn task_resp_serialization() { &[ Token::Struct { name: "TaskResp", - len: 16, + len: 15, }, Token::Str("task_id"), Token::Str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), @@ -1863,20 +1895,6 @@ fn task_resp_serialization() { Token::U64(60), Token::Str("aggregator_auth_token"), Token::None, - Token::Str("collector_auth_token"), - Token::Some, - Token::Struct { - name: "AuthenticationToken", - len: 2, - }, - Token::Str("type"), - Token::UnitVariant { - name: "AuthenticationToken", - variant: "DapAuth", - }, - Token::Str("token"), - Token::Str("Y29sbGVjdG9yLWFiY2RlZjAw"), - Token::StructEnd, Token::Str("collector_hpke_config"), Token::Struct { name: "HpkeConfig", diff --git a/aggregator_core/src/datastore.rs b/aggregator_core/src/datastore.rs index 358f14bbe..1299e0846 100644 --- a/aggregator_core/src/datastore.rs +++ b/aggregator_core/src/datastore.rs @@ -535,7 +535,7 @@ impl Transaction<'_, C> { max_batch_query_count, task_expiration, report_expiry_age, min_batch_size, time_precision, tolerable_clock_skew, collector_hpke_config, vdaf_verify_key, aggregator_auth_token_type, aggregator_auth_token, aggregator_auth_token_hash, - collector_auth_token_type, collector_auth_token) + collector_auth_token_type, collector_auth_token_hash) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18 ) @@ -605,20 +605,12 @@ impl Transaction<'_, C> { .map(|token_hash| token_hash.as_ref()), /* collector_auth_token_type */ &task - .collector_auth_token() + .collector_auth_token_hash() .map(AuthenticationTokenType::from), /* collector_auth_token */ &task - .collector_auth_token() - .map(|token| { - self.crypter.encrypt( - "tasks", - task.id().as_ref(), - "collector_auth_token", - token.as_ref(), - ) - }) - .transpose()?, + .collector_auth_token_hash() + .map(|token_hash| token_hash.as_ref()), ], ) .await?, @@ -693,7 +685,7 @@ impl Transaction<'_, C> { max_batch_query_count, task_expiration, report_expiry_age, min_batch_size, time_precision, tolerable_clock_skew, collector_hpke_config, vdaf_verify_key, aggregator_auth_token_type, aggregator_auth_token, aggregator_auth_token_hash, - collector_auth_token_type, collector_auth_token + collector_auth_token_type, collector_auth_token_hash FROM tasks WHERE task_id = $1", ) .await?; @@ -722,7 +714,7 @@ impl Transaction<'_, C> { max_batch_query_count, task_expiration, report_expiry_age, min_batch_size, time_precision, tolerable_clock_skew, collector_hpke_config, vdaf_verify_key, aggregator_auth_token_type, aggregator_auth_token, aggregator_auth_token_hash, - collector_auth_token_type, collector_auth_token + collector_auth_token_type, collector_auth_token_hash FROM tasks", ) .await?; @@ -829,17 +821,10 @@ impl Transaction<'_, C> { .map(|(token_hash, token_type)| token_type.as_authentication_token_hash(&token_hash)) .transpose()?; - let collector_auth_token = row - .try_get::<_, Option>>("collector_auth_token")? + let collector_auth_token_hash = row + .try_get::<_, Option>>("collector_auth_token_hash")? .zip(row.try_get::<_, Option>("collector_auth_token_type")?) - .map(|(encrypted_token, token_type)| { - token_type.as_authentication(&self.crypter.decrypt( - "tasks", - task_id.as_ref(), - "collector_auth_token", - &encrypted_token, - )?) - }) + .map(|(token_hash, token_type)| token_type.as_authentication_token_hash(&token_hash)) .transpose()?; // HPKE keys. @@ -867,18 +852,18 @@ impl Transaction<'_, C> { aggregator_role, aggregator_auth_token, aggregator_auth_token_hash, - collector_auth_token, + collector_auth_token_hash, collector_hpke_config, ) { ( AggregatorRole::Leader, Some(aggregator_auth_token), None, - Some(collector_auth_token), + Some(collector_auth_token_hash), Some(collector_hpke_config), ) => AggregatorTaskParameters::Leader { aggregator_auth_token, - collector_auth_token, + collector_auth_token_hash, collector_hpke_config, }, ( diff --git a/aggregator_core/src/datastore/tests.rs b/aggregator_core/src/datastore/tests.rs index a46b36ff3..4ae3f25a6 100644 --- a/aggregator_core/src/datastore/tests.rs +++ b/aggregator_core/src/datastore/tests.rs @@ -287,7 +287,7 @@ async fn put_task_invalid_collector_auth_tokens(ephemeral_datastore: EphemeralDa let err = tx .query_one( &format!( - "UPDATE tasks SET collector_auth_token = {auth_token}, + "UPDATE tasks SET collector_auth_token_hash = {auth_token}, collector_auth_token_type = {auth_token_type}" ), &[], diff --git a/aggregator_core/src/task.rs b/aggregator_core/src/task.rs index 293215c57..15446c298 100644 --- a/aggregator_core/src/task.rs +++ b/aggregator_core/src/task.rs @@ -433,10 +433,11 @@ impl AggregatorTask { self.aggregator_parameters.collector_hpke_config() } - /// Returns the collector authentication token for this task, if this aggregator is the leader. - /// TODO(#1509): make this an AuthenticationTokenHash - pub fn collector_auth_token(&self) -> Option<&AuthenticationToken> { - self.aggregator_parameters.collector_auth_token() + /// Returns the collector [`AuthenticationTokenHash`] for this task, used by the leader to + /// authenticate collection sub-protocol requests received from the collector, or `None` for the + /// helper. + pub fn collector_auth_token_hash(&self) -> Option<&AuthenticationTokenHash> { + self.aggregator_parameters.collector_auth_token_hash() } /// Return the HPKE keypairs used by this aggregator to decrypt client reports, or an empty map @@ -472,10 +473,7 @@ impl AggregatorTask { &self, incoming_auth_token: Option<&AuthenticationToken>, ) -> bool { - // TODO(#1509): Leader should hold only an AuthenticaitonTokenHash, making the - // AuthenticationTokenHash::from call here unnecessary. - self.collector_auth_token() - .map(AuthenticationTokenHash::from) + self.collector_auth_token_hash() .zip(incoming_auth_token) .map(|(own_token_hash, incoming_token)| own_token_hash.validate(incoming_token)) .unwrap_or(false) @@ -491,9 +489,9 @@ pub enum AggregatorTaskParameters { /// Authentication token used to make requests to the helper during the aggregation /// sub-protocol. aggregator_auth_token: AuthenticationToken, - /// Authentication token used to validate requests from the collector during the collection - /// sub-protocol. - collector_auth_token: AuthenticationToken, + /// Authentication token hash used to validate requests from the collector during the + /// collection sub-protocol. + collector_auth_token_hash: AuthenticationTokenHash, /// HPKE configuration for the collector. collector_hpke_config: HpkeConfig, }, @@ -559,14 +557,15 @@ impl AggregatorTaskParameters { } } - /// Returns the collector authentication token for this task, if this aggregator is the leader. - /// TODO(#1509): make this an AuthenticationTokenHash - fn collector_auth_token(&self) -> Option<&AuthenticationToken> { + /// Returns the collector [`AuthenticationTokenHash`] for this task, used by the leader to + /// authenticate collection sub-protocol requests received from the collector, or `None` for the + /// helper. + fn collector_auth_token_hash(&self) -> Option<&AuthenticationTokenHash> { match self { Self::Leader { - collector_auth_token, + collector_auth_token_hash, .. - } => Some(collector_auth_token), + } => Some(collector_auth_token_hash), _ => None, } } @@ -591,7 +590,7 @@ pub struct SerializedAggregatorTask { collector_hpke_config: HpkeConfig, aggregator_auth_token: Option, aggregator_auth_token_hash: Option, - collector_auth_token: Option, + collector_auth_token_hash: Option, hpke_keys: Vec, // uses unpadded base64url } @@ -671,7 +670,10 @@ impl Serialize for AggregatorTask { .aggregator_parameters .aggregator_auth_token_hash() .cloned(), - collector_auth_token: self.aggregator_parameters.collector_auth_token().cloned(), + collector_auth_token_hash: self + .aggregator_parameters + .collector_auth_token_hash() + .cloned(), hpke_keys, } .serialize(serializer) @@ -697,9 +699,9 @@ impl TryFrom for AggregatorTask { aggregator_auth_token: serialized_task .aggregator_auth_token .ok_or(Error::InvalidParameter("missing aggregator auth token"))?, - collector_auth_token: serialized_task - .collector_auth_token - .ok_or(Error::InvalidParameter("missing collector auth token"))?, + collector_auth_token_hash: serialized_task + .collector_auth_token_hash + .ok_or(Error::InvalidParameter("missing collector auth token hash"))?, collector_hpke_config: serialized_task.collector_hpke_config, }, Role::Helper => AggregatorTaskParameters::Helper { @@ -1005,7 +1007,9 @@ pub mod test_util { self.leader_hpke_keys.values().cloned().collect::>(), AggregatorTaskParameters::Leader { aggregator_auth_token: self.aggregator_auth_token.clone(), - collector_auth_token: self.collector_auth_token.clone(), + collector_auth_token_hash: AuthenticationTokenHash::from( + &self.collector_auth_token, + ), collector_hpke_config: self.collector_hpke_keypair.config().clone(), }, ) @@ -1445,10 +1449,10 @@ mod tests { "YWdncmVnYXRvciB0b2tlbg", ) .unwrap(), - collector_auth_token: AuthenticationToken::new_bearer_token_from_string( - "Y29sbGVjdG9yIHRva2Vu", - ) - .unwrap(), + collector_auth_token_hash: AuthenticationTokenHash::from( + &AuthenticationToken::new_bearer_token_from_string("Y29sbGVjdG9yIHRva2Vu") + .unwrap(), + ), collector_hpke_config: HpkeConfig::new( HpkeConfigId::from(8), HpkeKemId::X25519HkdfSha256, @@ -1545,19 +1549,19 @@ mod tests { Token::StructEnd, Token::Str("aggregator_auth_token_hash"), Token::None, - Token::Str("collector_auth_token"), + Token::Str("collector_auth_token_hash"), Token::Some, Token::Struct { - name: "AuthenticationToken", + name: "AuthenticationTokenHash", len: 2, }, Token::Str("type"), Token::UnitVariant { - name: "AuthenticationToken", + name: "AuthenticationTokenHash", variant: "Bearer", }, - Token::Str("token"), - Token::Str("Y29sbGVjdG9yIHRva2Vu"), + Token::Str("hash"), + Token::Str("LdjsTjGZXsaitZonqNIi2LcDLce3OLP6SeWv2eUx4rY"), Token::StructEnd, Token::Str("hpke_keys"), Token::Seq { len: Some(1) }, @@ -1747,7 +1751,7 @@ mod tests { Token::Str("hash"), Token::Str("MJOoBO_ysLEuG_lv2C37eEOf1Ngetsr-Ers0ZYj4vdQ"), Token::StructEnd, - Token::Str("collector_auth_token"), + Token::Str("collector_auth_token_hash"), Token::None, Token::Str("hpke_keys"), Token::Seq { len: Some(1) }, diff --git a/db/00000000000001_initial_schema.up.sql b/db/00000000000001_initial_schema.up.sql index 110b911a0..ddebd8ed6 100644 --- a/db/00000000000001_initial_schema.up.sql +++ b/db/00000000000001_initial_schema.up.sql @@ -107,9 +107,9 @@ CREATE TABLE tasks( -- Authentication token used to authenticate messages to the leader from the collector. These -- columns are NULL if the task was provisioned by taskprov or if the task's role is helper. collector_auth_token_type AUTH_TOKEN_TYPE, -- the type of the authentication token - collector_auth_token BYTEA, -- encrypted bearer token + collector_auth_token_hash BYTEA, -- hash of the token -- The collector_auth_token columns must either both be NULL or both be non-NULL - CONSTRAINT collector_auth_token_null CHECK ((collector_auth_token_type IS NULL) = (collector_auth_token IS NULL)) + CONSTRAINT collector_auth_token_null CHECK ((collector_auth_token_type IS NULL) = (collector_auth_token_hash IS NULL)) ); CREATE INDEX task_id_index ON tasks(task_id); diff --git a/docs/samples/tasks.yaml b/docs/samples/tasks.yaml index 2c003e628..c6afdbdd1 100644 --- a/docs/samples/tasks.yaml +++ b/docs/samples/tasks.yaml @@ -70,15 +70,18 @@ type: "DapAuth" token: "YWdncmVnYXRvci0yMzUyNDJmOTk0MDZjNGZkMjhiODIwYzMyZWFiMGY2OA" - # Authentication token shared between the leader and the collector, and used - # to authenticate collector-to-leader requests. For leader tasks, this has the - # same format as `aggregator_auth_tokens` above. For helper tasks, this will - # be an empty list instead. - # Bearer token values are encoded in unpadded base64url. - # This example decodes to "collector-abf5408e2b1601831625af3959106458". - collector_auth_token: + # Authentication token hash used by the leader to authenticate requests + # received from the collector. This value should only be included in + # leader-role tasks. + # + # The `type` corresponds to the `type` of an `aggregator_auth_token` stanza, + # and the leader will only accept the auth token if it is presented in a + # request in the indicated manner. + # + # `hash` is the SHA-256 hash of the token value, encoded in unpadded base64url. + collector_auth_token_hash: type: "Bearer" - token: "Y29sbGVjdG9yLWFiZjU0MDhlMmIxNjAxODMxNjI1YWYzOTU5MTA2NDU4" + hash: "MJOoBO_ysLEuG_lv2C37eEOf1Ngetsr-Ers0ZYj4vdQ" # This aggregator's HPKE keypairs. The first keypair's HPKE configuration will # be served via the `hpke_config` DAP endpoint. All keypairs will be tried diff --git a/interop_binaries/src/bin/janus_interop_aggregator.rs b/interop_binaries/src/bin/janus_interop_aggregator.rs index 97bbbe13d..1e683de2f 100644 --- a/interop_binaries/src/bin/janus_interop_aggregator.rs +++ b/interop_binaries/src/bin/janus_interop_aggregator.rs @@ -68,10 +68,12 @@ async fn handle_add_task( (AggregatorRole::Leader, Some(collector_authentication_token)) => { AggregatorTaskParameters::Leader { aggregator_auth_token: leader_authentication_token, - collector_auth_token: AuthenticationToken::new_dap_auth_token_from_string( - collector_authentication_token, - ) - .context("invalid header value in \"collector_authentication_token\"")?, + collector_auth_token_hash: AuthenticationTokenHash::from( + &AuthenticationToken::new_dap_auth_token_from_string( + collector_authentication_token, + ) + .context("invalid header value in \"collector_authentication_token\"")?, + ), collector_hpke_config, } }