snap_control/pg_wap/crpc/
handler.rs1use std::{net::IpAddr, time::SystemTime};
18
19use crate::pg_wap::{
20 crpc::model::{
21 AuthorizeTargetsError, AuthorizeTargetsRequest, AuthorizeTargetsResponse,
22 ControlServiceAPIHandler,
23 },
24 grants::{AuthorizeError, GrantManager},
25};
26
27pub struct WapControlHandler {
33 grant: GrantManager,
35 wap_id: String,
37 data_plane_port: u16,
39}
40
41impl WapControlHandler {
42 pub fn new(grant: GrantManager, wap_id: String, data_plane_port: u16) -> Self {
47 Self {
48 grant,
49 wap_id,
50 data_plane_port,
51 }
52 }
53}
54
55impl ControlServiceAPIHandler for WapControlHandler {
56 fn authorize_targets(
57 &self,
58 client_ip: IpAddr,
59 request: AuthorizeTargetsRequest,
60 now: SystemTime,
61 ) -> Result<AuthorizeTargetsResponse, AuthorizeTargetsError> {
62 let expiry_time = self
63 .grant
64 .authorize(client_ip, request.targets, now)
65 .map_err(|err| {
66 let message = err.to_string();
67
68 match err {
69 AuthorizeError::TooManySegmentsInRequest { .. }
72 | AuthorizeError::TooManyTargetsInRequest { .. }
73 | AuthorizeError::TooManySegmentsForTarget { .. }
74 | AuthorizeError::TooManyTargetsForIp { .. } => {
75 AuthorizeTargetsError::InvalidRequest(message)
76 }
77 AuthorizeError::TargetGrantLimitReached { .. }
80 | AuthorizeError::IpTargetLimitReached { .. } => {
81 AuthorizeTargetsError::LimitReached(message)
82 }
83 }
84 })?;
85
86 Ok(AuthorizeTargetsResponse {
87 client_ip,
88 wap_id: self.wap_id.clone(),
89 data_plane_port: self.data_plane_port,
90 expiry_time,
91 })
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use std::{
98 collections::BTreeMap,
99 net::Ipv4Addr,
100 time::{Duration, UNIX_EPOCH},
101 };
102
103 use super::*;
104 use crate::pg_wap::{
105 crpc::model::AuthSegments, grants::GrantManagerConfig, sni::CustomerDomain,
106 };
107
108 const GRANT_DURATION: Duration = Duration::from_secs(100);
109 const WAP_ID: &str = "wap-1";
110 const DATA_PLANE_PORT: u16 = 8443;
111
112 fn handler(max_targets: usize) -> WapControlHandler {
115 let grant = GrantManager::new(GrantManagerConfig {
116 grant_duration: GRANT_DURATION,
117 max_targets_per_request: max_targets,
118 ..GrantManagerConfig::default()
119 })
120 .expect("a valid GrantManagerConfig");
121
122 WapControlHandler::new(grant, WAP_ID.to_owned(), DATA_PLANE_PORT)
123 }
124
125 fn request(count: usize) -> AuthorizeTargetsRequest {
127 AuthorizeTargetsRequest {
128 targets: (0..count)
129 .map(|i| {
130 (
131 CustomerDomain::new(format!("target{i}.example.com"))
132 .expect("a valid domain"),
133 AuthSegments::default(),
134 )
135 })
136 .collect::<BTreeMap<_, _>>(),
137 }
138 }
139
140 #[test]
141 fn response_carries_the_wap_and_the_granted_expiry() {
142 let client_ip = Ipv4Addr::new(192, 0, 2, 1).into();
143 let now = UNIX_EPOCH + Duration::from_secs(1_000);
144
145 let response = handler(10)
146 .authorize_targets(client_ip, request(1), now)
147 .expect("the grant fits");
148
149 assert_eq!(response.client_ip, client_ip);
150 assert_eq!(response.wap_id, WAP_ID);
151 assert_eq!(response.data_plane_port, DATA_PLANE_PORT);
152 assert_eq!(response.expiry_time, now + GRANT_DURATION);
153 }
154
155 #[test]
156 fn a_request_over_a_limit_is_invalid() {
157 let err = handler(1)
158 .authorize_targets(
159 Ipv4Addr::new(192, 0, 2, 1).into(),
160 request(2),
161 SystemTime::now(),
162 )
163 .expect_err("two targets do not fit");
164
165 assert!(matches!(err, AuthorizeTargetsError::InvalidRequest(_)));
166 }
167}