@@ -110,20 +110,32 @@ impl Default for SessionConfig {
110110}
111111
112112impl SessionConfig {
113+ /// Minimum allowed value for max_sessions_per_user.
114+ pub const MIN_SESSIONS_PER_USER : usize = 1 ;
115+
116+ /// Minimum allowed value for max_total_sessions.
117+ pub const MIN_TOTAL_SESSIONS : usize = 1 ;
118+
113119 /// Create a new session configuration with default values.
114120 pub fn new ( ) -> Self {
115121 Self :: default ( )
116122 }
117123
118124 /// Set the maximum sessions per user.
125+ ///
126+ /// The value is clamped to a minimum of 1 to prevent misconfiguration
127+ /// that would deny all users from authenticating.
119128 pub fn with_max_sessions_per_user ( mut self , max : usize ) -> Self {
120- self . max_sessions_per_user = max;
129+ self . max_sessions_per_user = max. max ( Self :: MIN_SESSIONS_PER_USER ) ;
121130 self
122131 }
123132
124133 /// Set the maximum total sessions.
134+ ///
135+ /// The value is clamped to a minimum of 1 to prevent misconfiguration
136+ /// that would deny all connections.
125137 pub fn with_max_total_sessions ( mut self , max : usize ) -> Self {
126- self . max_total_sessions = max;
138+ self . max_total_sessions = max. max ( Self :: MIN_TOTAL_SESSIONS ) ;
127139 self
128140 }
129141
@@ -138,6 +150,35 @@ impl SessionConfig {
138150 self . session_timeout = Some ( timeout) ;
139151 self
140152 }
153+
154+ /// Validate the configuration and return any warnings.
155+ ///
156+ /// Returns a list of warning messages for potentially problematic settings.
157+ pub fn validate ( & self ) -> Vec < String > {
158+ let mut warnings = Vec :: new ( ) ;
159+
160+ if self . max_sessions_per_user > self . max_total_sessions {
161+ warnings. push ( format ! (
162+ "max_sessions_per_user ({}) > max_total_sessions ({}) - per-user limit will never be reached" ,
163+ self . max_sessions_per_user, self . max_total_sessions
164+ ) ) ;
165+ }
166+
167+ if self . idle_timeout . as_secs ( ) == 0 {
168+ warnings. push ( "idle_timeout is 0 - sessions will be immediately considered idle" . to_string ( ) ) ;
169+ }
170+
171+ if let Some ( session_timeout) = self . session_timeout {
172+ if session_timeout < self . idle_timeout {
173+ warnings. push ( format ! (
174+ "session_timeout ({:?}) < idle_timeout ({:?}) - sessions may be terminated before idle check" ,
175+ session_timeout, self . idle_timeout
176+ ) ) ;
177+ }
178+ }
179+
180+ warnings
181+ }
141182}
142183
143184/// Errors that can occur during session management.
@@ -181,9 +222,13 @@ pub struct SessionId(u64);
181222
182223impl SessionId {
183224 /// Create a new unique session ID.
225+ ///
226+ /// Uses `Ordering::SeqCst` to ensure session IDs are strictly ordered
227+ /// across all threads, preventing potential confusion in logging and
228+ /// debugging when sessions appear out of order.
184229 pub fn new ( ) -> Self {
185230 static COUNTER : AtomicU64 = AtomicU64 :: new ( 1 ) ;
186- Self ( COUNTER . fetch_add ( 1 , Ordering :: Relaxed ) )
231+ Self ( COUNTER . fetch_add ( 1 , Ordering :: SeqCst ) )
187232 }
188233
189234 /// Get the raw numeric value of the session ID.
@@ -968,6 +1013,41 @@ mod tests {
9681013 assert_eq ! ( config. session_timeout, Some ( Duration :: from_secs( 86400 ) ) ) ;
9691014 }
9701015
1016+ #[ test]
1017+ fn test_session_config_validation_clamping ( ) {
1018+ // Setting max_sessions_per_user to 0 should clamp to 1
1019+ let config = SessionConfig :: new ( ) . with_max_sessions_per_user ( 0 ) ;
1020+ assert_eq ! ( config. max_sessions_per_user, 1 ) ;
1021+
1022+ // Setting max_total_sessions to 0 should clamp to 1
1023+ let config = SessionConfig :: new ( ) . with_max_total_sessions ( 0 ) ;
1024+ assert_eq ! ( config. max_total_sessions, 1 ) ;
1025+ }
1026+
1027+ #[ test]
1028+ fn test_session_config_validate ( ) {
1029+ // Valid config should have no warnings
1030+ let config = SessionConfig :: new ( ) ;
1031+ let warnings = config. validate ( ) ;
1032+ assert ! ( warnings. is_empty( ) ) ;
1033+
1034+ // Per-user > total should warn
1035+ let config = SessionConfig :: new ( )
1036+ . with_max_sessions_per_user ( 100 )
1037+ . with_max_total_sessions ( 10 ) ;
1038+ let warnings = config. validate ( ) ;
1039+ assert_eq ! ( warnings. len( ) , 1 ) ;
1040+ assert ! ( warnings[ 0 ] . contains( "per-user limit" ) ) ;
1041+
1042+ // Session timeout < idle timeout should warn
1043+ let config = SessionConfig :: new ( )
1044+ . with_idle_timeout ( Duration :: from_secs ( 3600 ) )
1045+ . with_session_timeout ( Duration :: from_secs ( 1800 ) ) ;
1046+ let warnings = config. validate ( ) ;
1047+ assert_eq ! ( warnings. len( ) , 1 ) ;
1048+ assert ! ( warnings[ 0 ] . contains( "session_timeout" ) ) ;
1049+ }
1050+
9711051 #[ test]
9721052 fn test_session_manager_creation ( ) {
9731053 let manager = SessionManager :: new ( ) ;
0 commit comments