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::{SessionManager, SessionOpenError, 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
81impl Default for SessionManagerState {
82 fn default() -> Self {
83 Self::new(DEFAULT_SESSION_DURATION)
84 }
85}
86
87pub struct SessionGrant {
89 expiry: SystemTime,
91}
92
93impl SessionManager for SessionManagerState {
94 fn open(
99 &mut self,
100 pssid: Pssid,
101 data_plane_id: DataPlaneId,
102 ) -> Result<SessionGrant, SessionOpenError> {
103 let session_id = SessionId::new(pssid.clone(), data_plane_id);
104 let session_expiry = SystemTime::now() + self.session_duration;
105
106 let _res = self
109 .sessions
110 .insert(session_id, Session::new(session_expiry));
111
112 Ok(SessionGrant {
113 expiry: session_expiry,
114 })
115 }
116}
117
118#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
120pub struct Session {
121 expiry: SystemTime,
122}
123
124impl Session {
125 fn new(expiry: SystemTime) -> Self {
126 Self { expiry }
127 }
128}
129
130#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
133pub struct SessionTokenIssuerState {
134 key: Ed25519SigningKeyPem,
136}
137
138impl SessionTokenIssuerState {
139 pub fn new(key: Ed25519SigningKeyPem) -> Self {
141 Self { key }
142 }
143}
144
145impl TokenIssuer for SessionTokenIssuerState {
146 fn issue(
147 &self,
148 pssid: Pssid,
149 data_plane_id: DataPlaneId,
150 session_grant: SessionGrant,
151 ) -> Result<String, SessionTokenError> {
152 let claims = SessionTokenClaims {
153 pssid,
154 data_plane_id: data_plane_id.as_usize(),
155 exp: session_grant
156 .expiry
157 .duration_since(UNIX_EPOCH)
158 .unwrap()
159 .as_secs(),
160 };
161
162 let encoding_key = (&self.key).into();
163 let token = jsonwebtoken::encode(&Header::new(Algorithm::EdDSA), &claims, &encoding_key)
164 .map_err(SessionTokenError::EncodingError)?;
165 Ok(token)
166 }
167}
168
169pub fn insecure_const_session_key_pair(input: usize) -> (EncodingKey, DecodingKey) {
173 let (private_pem, public_pem) = insecure_const_session_key_pair_pem(input);
174
175 let encoding_key = EncodingKey::from_ed_pem(pem::encode(&private_pem).as_bytes()).unwrap();
176 let decoding_key = DecodingKey::from_ed_pem(pem::encode(&public_pem).as_bytes()).unwrap();
177
178 (encoding_key, decoding_key)
179}
180
181pub fn insecure_const_session_key_pair_pem(input: usize) -> (Pem, Pem) {
185 let dalek_keypair = insecure_const_ed25519_signing_key(input);
186 let public_key =
187 ed25519_dalek::pkcs8::PublicKeyBytes(*dalek_keypair.verifying_key().as_bytes());
188
189 let kp = ed25519_dalek::pkcs8::KeypairBytes {
190 secret_key: *dalek_keypair.as_bytes(),
191 public_key: Some(public_key),
192 };
193
194 let private_pem = pem::Pem::new("PRIVATE KEY", kp.to_pkcs8_der().unwrap().as_bytes());
195
196 let public_pem = pem::Pem::new(
197 "PUBLIC KEY",
198 public_key.to_public_key_der().unwrap().as_bytes(),
199 );
200
201 (private_pem, public_pem)
202}
203
204pub fn insecure_const_ed25519_signing_key(input: usize) -> SigningKey {
206 let mut seed = [43u8; 32];
207 let id_bytes = input.to_le_bytes();
208 seed[..id_bytes.len()].copy_from_slice(&id_bytes);
209
210 ed25519_dalek::SigningKey::from_bytes(&seed)
211}
212
213pub fn random_ed25519_signing_key() -> SigningKey {
215 let mut trng = rand::rng();
216 let mut seed = [0u8; 32];
217 trng.fill_bytes(&mut seed[..]);
218
219 ed25519_dalek::SigningKey::from_bytes(&seed)
220}
221
222#[cfg(test)]
223mod tests {
224 use std::time::{Duration, UNIX_EPOCH};
225
226 use scion_sdk_token_validator::validator::{TokenValidator, Validator};
227 use snap_tokens::snap_token::SnapTokenClaims;
228 use test_log::test;
229 use uuid::Uuid;
230
231 use super::*;
232
233 #[test]
234 fn session_mgmt() {
235 let claims = SnapTokenClaims {
236 pssid: Pssid(Uuid::new_v4()),
237 exp: (SystemTime::now() + Duration::from_secs(360))
238 .duration_since(UNIX_EPOCH)
239 .unwrap()
240 .as_secs(),
241 };
242 let dp_id = DataPlaneId::from_usize(0);
243
244 let signing_key = insecure_const_ed25519_signing_key(0);
245 let signing_key = Ed25519SigningKeyPem::from(signing_key);
246 let decoding_key = signing_key.to_decoding_key();
247 let issuer = SessionTokenIssuerState::new(signing_key);
248
249 let mut session_manager = SessionManagerState::default();
250
251 let session_grant = session_manager.open(claims.pssid.clone(), dp_id).unwrap();
252
253 let session_token = issuer
254 .issue(claims.pssid.clone(), dp_id, session_grant)
255 .unwrap();
256
257 Validator::<SessionTokenClaims>::new(decoding_key, None)
258 .validate(SystemTime::now(), &session_token)
259 .expect("validation failed");
260
261 let _ = session_manager
263 .open(claims.pssid.clone(), dp_id)
264 .expect("open second session");
265 }
266}