1use std::{
17 collections::BTreeMap,
18 time::{Duration, SystemTime, UNIX_EPOCH},
19};
20
21use ed25519_dalek::{
22 SigningKey,
23 pkcs8::{EncodePrivateKey, EncodePublicKey},
24};
25use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header};
26use pem::Pem;
27use rand::RngCore;
28use scion_sdk_common_types::ed25519::Ed25519SigningKeyPem;
29use serde::{Deserialize, Serialize};
30use snap_tokens::{Pssid, session_token::SessionTokenClaims};
31
32use super::manager::{SessionTokenError, TokenIssuer};
33use crate::state::{DataPlaneId, Id};
34
35pub mod dto;
36
37const DEFAULT_SESSION_DURATION: Duration = Duration::from_secs(3600); #[derive(Debug, Ord, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Clone)]
41pub struct SessionId {
42 pssid: Pssid,
43 data_plane_id: DataPlaneId,
44}
45
46impl SessionId {
47 pub fn new(pssid: Pssid, data_plane_id: DataPlaneId) -> Self {
49 Self {
50 pssid,
51 data_plane_id,
52 }
53 }
54}
55
56#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
64pub struct SessionManagerState {
65 session_duration: Duration,
67 sessions: BTreeMap<SessionId, Session>,
69}
70
71impl SessionManagerState {
72 pub fn new(session_duration: Duration) -> Self {
74 Self {
75 session_duration,
76 sessions: BTreeMap::new(),
77 }
78 }
79
80 pub fn open(
84 &mut self,
85 pssid: Pssid,
86 data_plane_id: DataPlaneId,
87 ) -> Result<SessionGrant, SessionOpenError> {
88 let session_id = SessionId::new(pssid.clone(), data_plane_id);
89 let session_expiry = SystemTime::now() + self.session_duration;
90
91 let _res = self
94 .sessions
95 .insert(session_id, Session::new(session_expiry));
96
97 Ok(SessionGrant {
98 expiry: session_expiry,
99 })
100 }
101}
102
103#[derive(Debug, thiserror::Error)]
105pub enum SessionOpenError {}
106
107impl Default for SessionManagerState {
108 fn default() -> Self {
109 Self::new(DEFAULT_SESSION_DURATION)
110 }
111}
112
113pub struct SessionGrant {
115 expiry: SystemTime,
117}
118
119#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
121pub struct Session {
122 expiry: SystemTime,
123}
124
125impl Session {
126 fn new(expiry: SystemTime) -> Self {
127 Self { expiry }
128 }
129}
130
131#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
134pub struct SessionTokenIssuerState {
135 key: Ed25519SigningKeyPem,
137}
138
139impl SessionTokenIssuerState {
140 pub fn new(key: Ed25519SigningKeyPem) -> Self {
142 Self { key }
143 }
144}
145
146impl TokenIssuer for SessionTokenIssuerState {
147 fn issue(
148 &self,
149 pssid: Pssid,
150 data_plane_id: DataPlaneId,
151 session_grant: SessionGrant,
152 ) -> Result<String, SessionTokenError> {
153 let claims = SessionTokenClaims {
154 pssid,
155 data_plane_id: data_plane_id.as_usize(),
156 exp: session_grant
157 .expiry
158 .duration_since(UNIX_EPOCH)
159 .unwrap()
160 .as_secs(),
161 };
162
163 let encoding_key = (&self.key).into();
164 let token = jsonwebtoken::encode(&Header::new(Algorithm::EdDSA), &claims, &encoding_key)
165 .map_err(SessionTokenError::EncodingError)?;
166 Ok(token)
167 }
168}
169
170pub fn insecure_const_session_key_pair(input: usize) -> (EncodingKey, DecodingKey) {
174 let (private_pem, public_pem) = insecure_const_session_key_pair_pem(input);
175
176 let encoding_key = EncodingKey::from_ed_pem(pem::encode(&private_pem).as_bytes()).unwrap();
177 let decoding_key = DecodingKey::from_ed_pem(pem::encode(&public_pem).as_bytes()).unwrap();
178
179 (encoding_key, decoding_key)
180}
181
182pub fn insecure_const_session_key_pair_pem(input: usize) -> (Pem, Pem) {
186 let dalek_keypair = insecure_const_ed25519_signing_key(input);
187 let public_key =
188 ed25519_dalek::pkcs8::PublicKeyBytes(*dalek_keypair.verifying_key().as_bytes());
189
190 let kp = ed25519_dalek::pkcs8::KeypairBytes {
191 secret_key: *dalek_keypair.as_bytes(),
192 public_key: Some(public_key),
193 };
194
195 let private_pem = pem::Pem::new("PRIVATE KEY", kp.to_pkcs8_der().unwrap().as_bytes());
196
197 let public_pem = pem::Pem::new(
198 "PUBLIC KEY",
199 public_key.to_public_key_der().unwrap().as_bytes(),
200 );
201
202 (private_pem, public_pem)
203}
204
205pub fn insecure_const_ed25519_signing_key(input: usize) -> SigningKey {
207 let mut seed = [43u8; 32];
208 let id_bytes = input.to_le_bytes();
209 seed[..id_bytes.len()].copy_from_slice(&id_bytes);
210
211 ed25519_dalek::SigningKey::from_bytes(&seed)
212}
213
214pub fn random_ed25519_signing_key() -> SigningKey {
216 let mut trng = rand::rng();
217 let mut seed = [0u8; 32];
218 trng.fill_bytes(&mut seed[..]);
219
220 ed25519_dalek::SigningKey::from_bytes(&seed)
221}
222
223#[cfg(test)]
224mod tests {
225 use std::time::{Duration, UNIX_EPOCH};
226
227 use scion_sdk_token_validator::validator::{TokenValidator, Validator};
228 use snap_tokens::snap_token::SnapTokenClaims;
229 use test_log::test;
230 use uuid::Uuid;
231
232 use super::*;
233
234 #[test]
235 fn session_mgmt() {
236 let claims = SnapTokenClaims {
237 pssid: Pssid(Uuid::new_v4()),
238 exp: (SystemTime::now() + Duration::from_secs(360))
239 .duration_since(UNIX_EPOCH)
240 .unwrap()
241 .as_secs(),
242 };
243 let dp_id = DataPlaneId::from_usize(0);
244
245 let signing_key = insecure_const_ed25519_signing_key(0);
246 let signing_key = Ed25519SigningKeyPem::from(signing_key);
247 let decoding_key = signing_key.to_decoding_key();
248 let issuer = SessionTokenIssuerState::new(signing_key);
249
250 let mut session_manager = SessionManagerState::default();
251
252 let session_grant = session_manager.open(claims.pssid.clone(), dp_id).unwrap();
253
254 let session_token = issuer
255 .issue(claims.pssid.clone(), dp_id, session_grant)
256 .unwrap();
257
258 Validator::<SessionTokenClaims>::new(decoding_key, None)
259 .validate(SystemTime::now(), &session_token)
260 .expect("validation failed");
261
262 let _ = session_manager
264 .open(claims.pssid.clone(), dp_id)
265 .expect("open second session");
266 }
267}