Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/architecture/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ security:
# Idle session timeout (seconds, 0 to disable)
idle_timeout: 3600 # Default: 3600 (1 hour)

# Maximum session duration (seconds, 0 to disable)
# Sessions are terminated after this duration regardless of activity
session_timeout: 0 # Default: 0 (disabled)

# IP allowlist (CIDR notation, empty = allow all)
# When configured, only connections from these ranges are allowed
allowed_ips:
Expand Down Expand Up @@ -643,6 +647,100 @@ scp -rp ./data/ user@bssh-server:/storage/backup/

---

## Session Management

The server implements comprehensive session management with per-user limits, idle timeout detection, and session tracking.

### Session Configuration

Session management is configured through the `SessionConfig` structure:

```rust
use bssh::server::session::SessionConfig;
use std::time::Duration;

let config = SessionConfig::new()
.with_max_sessions_per_user(10) // Max sessions per authenticated user
.with_max_total_sessions(1000) // Max total concurrent sessions
.with_idle_timeout(Duration::from_secs(3600)) // 1 hour idle timeout
.with_session_timeout(Duration::from_secs(86400)); // 24 hour max duration
```

### Session Limits

**Per-User Session Limits:**
- Each authenticated user has a configurable maximum number of concurrent sessions
- When a user exceeds their limit, authentication is rejected with an error
- Default: 10 sessions per user

**Total Session Limits:**
- The server enforces a global maximum number of concurrent sessions
- New connections are rejected when the limit is reached
- Default: 1000 total sessions (matches `max_connections`)

### Session Timeouts

**Idle Timeout:**
- Sessions with no activity for the configured duration are marked as idle
- The `cleanup_idle_sessions()` method removes idle unauthenticated sessions
- Default: 1 hour (3600 seconds)

**Session Timeout:**
- Optional maximum session duration regardless of activity
- Sessions exceeding this duration are eligible for termination
- Default: disabled (0)

### Session Activity Tracking

Each session tracks:
- **Session ID**: Unique identifier for the session
- **User**: Authenticated username (if authenticated)
- **Peer Address**: Remote client IP and port
- **Started At**: Timestamp of session creation
- **Last Activity**: Timestamp of last activity (updated via `touch()`)
- **Authentication State**: Whether the session is authenticated
- **Auth Attempts**: Number of authentication attempts

### Session Statistics

The `SessionManager` provides session statistics:

```rust
let stats = manager.get_stats();
println!("Total sessions: {}", stats.total_sessions);
println!("Authenticated: {}", stats.authenticated_sessions);
println!("Unique users: {}", stats.unique_users);
println!("Idle sessions: {}", stats.idle_sessions);
```

### Admin Operations

The session manager supports administrative operations:

```rust
// List all sessions
let sessions = manager.list_sessions();

// List sessions for a specific user
let user_sessions = manager.list_user_sessions("username");

// Force disconnect a session
manager.kill_session(session_id);

// Force disconnect all sessions for a user
let count = manager.kill_user_sessions("username");
```

### Configuration Validation

The `SessionConfig::validate()` method checks for potentially problematic settings and returns warnings:

- Warning if `max_sessions_per_user` > `max_total_sessions` (per-user limit will never be reached)
- Warning if `idle_timeout` is 0 (sessions immediately considered idle)
- Warning if `session_timeout` < `idle_timeout` (sessions may be terminated before idle check)

---

**Related Documentation:**
- [Server CLI Binary](../../ARCHITECTURE.md#server-cli-binary)
- [SSH Server Module](../../ARCHITECTURE.md#ssh-server-module)
Expand Down
61 changes: 61 additions & 0 deletions src/server/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,23 @@ pub struct ServerConfig {
/// Blocked IPs take priority over allowed IPs.
#[serde(default)]
pub blocked_ips: Vec<String>,

/// Maximum number of concurrent sessions per user.
///
/// Default: 10
#[serde(default = "default_max_sessions_per_user")]
pub max_sessions_per_user: usize,

/// Maximum session duration in seconds (optional).
///
/// If set to 0, sessions have no maximum duration.
/// Default: 0 (disabled)
#[serde(default)]
pub session_timeout_secs: u64,
}

fn default_max_sessions_per_user() -> usize {
10
}

/// Serializable configuration for public key authentication.
Expand Down Expand Up @@ -281,6 +298,8 @@ impl Default for ServerConfig {
whitelist_ips: Vec::new(),
allowed_ips: Vec::new(),
blocked_ips: Vec::new(),
max_sessions_per_user: default_max_sessions_per_user(),
session_timeout_secs: 0,
}
}
}
Expand Down Expand Up @@ -312,6 +331,34 @@ impl ServerConfig {
}
}

/// Get the session timeout as a Duration.
///
/// Returns `None` if session timeout is disabled (set to 0).
pub fn session_timeout(&self) -> Option<Duration> {
if self.session_timeout_secs == 0 {
None
} else {
Some(Duration::from_secs(self.session_timeout_secs))
}
}

/// Create a SessionConfig from the server configuration.
pub fn session_config(&self) -> super::session::SessionConfig {
let mut config = super::session::SessionConfig::new()
.with_max_sessions_per_user(self.max_sessions_per_user)
.with_max_total_sessions(self.max_connections);

if self.idle_timeout_secs > 0 {
config = config.with_idle_timeout(Duration::from_secs(self.idle_timeout_secs));
}

if self.session_timeout_secs > 0 {
config = config.with_session_timeout(Duration::from_secs(self.session_timeout_secs));
}

config
}

/// Check if any host keys are configured.
pub fn has_host_keys(&self) -> bool {
!self.host_keys.is_empty()
Expand Down Expand Up @@ -517,6 +564,18 @@ impl ServerConfigBuilder {
self
}

/// Set the maximum sessions per user.
pub fn max_sessions_per_user(mut self, max: usize) -> Self {
self.config.max_sessions_per_user = max;
self
}

/// Set the session timeout in seconds.
pub fn session_timeout_secs(mut self, secs: u64) -> Self {
self.config.session_timeout_secs = secs;
self
}

/// Build the ServerConfig.
pub fn build(self) -> ServerConfig {
self.config
Expand Down Expand Up @@ -581,6 +640,8 @@ impl ServerFileConfig {
whitelist_ips: self.security.whitelist_ips,
allowed_ips: self.security.allowed_ips,
blocked_ips: self.security.blocked_ips,
max_sessions_per_user: self.security.max_sessions_per_user,
session_timeout_secs: self.security.session_timeout,
}
}
}
Expand Down
16 changes: 13 additions & 3 deletions src/server/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ pub struct SecurityConfig {
/// Maximum number of concurrent sessions per user.
///
/// Default: 10
#[serde(default = "default_max_sessions")]
#[serde(default = "default_max_sessions_per_user")]
pub max_sessions_per_user: usize,

/// Idle session timeout in seconds.
Expand All @@ -405,6 +405,15 @@ pub struct SecurityConfig {
#[serde(default = "default_idle_timeout")]
pub idle_timeout: u64,

/// Maximum session duration in seconds (optional).
///
/// If set, sessions are terminated after this duration regardless of activity.
/// Set to 0 to disable.
///
/// Default: 0 (disabled)
#[serde(default)]
pub session_timeout: u64,

/// Allowed IP ranges in CIDR notation.
///
/// If non-empty, only connections from these ranges are allowed.
Expand Down Expand Up @@ -473,7 +482,7 @@ fn default_ban_time() -> u64 {
300
}

fn default_max_sessions() -> usize {
fn default_max_sessions_per_user() -> usize {
10
}

Expand Down Expand Up @@ -540,8 +549,9 @@ impl Default for SecurityConfig {
auth_window: default_auth_window(),
ban_time: default_ban_time(),
whitelist_ips: Vec::new(),
max_sessions_per_user: default_max_sessions(),
max_sessions_per_user: default_max_sessions_per_user(),
idle_timeout: default_idle_timeout(),
session_timeout: 0,
allowed_ips: Vec::new(),
blocked_ips: Vec::new(),
}
Expand Down
Loading
Loading