Skip to content

Commit cce72c6

Browse files
authored
feat: Implement public key authentication for server (#147)
* feat: Implement public key authentication for server Add authentication provider infrastructure for bssh-server: - Create AuthProvider trait for extensible auth backends - Implement PublicKeyVerifier with OpenSSH authorized_keys parsing - Support both directory and pattern-based authorized_keys locations - Integrate auth provider with SSH handler for auth_publickey - Add rate limiting for authentication attempts - Include comprehensive security features: - Username validation to prevent path traversal - File permission checks on Unix systems - Logging for auth attempts (success/failure) Configuration supports two modes: - Directory mode: {dir}/{username}/authorized_keys - Pattern mode: /home/{user}/.ssh/authorized_keys Closes #126 * fix: address critical and high severity security issues in public key authentication CRITICAL Issue Fixed: - Fix TOCTOU race condition in load_authorized_keys by removing path.exists() check and handling NotFound from read operation. Use symlink_metadata to detect symlinks before reading. HIGH Severity Issues Fixed: - Add group-writable permission check (0o020) in check_file_permissions - Fix user enumeration timing attack in user_exists by using constant-time behavior - always perform same operations regardless of username validity - Add directory ownership and permission validation in load_authorized_keys - Fix symlink check in get_user_info to use symlink_metadata MEDIUM Issue Fixed: - Share rate limiter across handlers via Arc to provide server-wide rate limiting instead of per-instance limiting Security Improvements: - Use symlink_metadata consistently to avoid following symlinks - Validate parent directory permissions (not world-writable, warn on group-writable) - Check ownership consistency between file and parent directory - Reject both world-writable and group-writable authorized_keys files - Prevent user enumeration through timing attacks All tests pass with cargo test and cargo clippy. * chore: finalize PR with documentation and formatting - Update ARCHITECTURE.md with comprehensive auth module documentation - Add authentication module reference to docs/architecture/README.md - Apply cargo fmt formatting to publickey.rs
1 parent 1f2ac4f commit cce72c6

8 files changed

Lines changed: 1466 additions & 16 deletions

File tree

ARCHITECTURE.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,21 +198,25 @@ SSH server implementation using the russh library for accepting incoming connect
198198
- `config.rs` - `ServerConfig` with builder pattern for server settings
199199
- `handler.rs` - `SshHandler` implementing `russh::server::Handler` trait
200200
- `session.rs` - Session state management (`SessionManager`, `SessionInfo`, `ChannelState`)
201+
- `auth/` - Authentication provider infrastructure
201202

202203
**Key Components**:
203204

204205
- **BsshServer**: Main server struct managing the SSH server lifecycle
205206
- Accepts connections on configured address
206207
- Loads host keys from OpenSSH format files
207208
- Configures russh with authentication settings
209+
- Creates shared rate limiter for authentication attempts
208210

209211
- **ServerConfig**: Configuration options with builder pattern
210212
- Host key paths and listen address
211213
- Connection limits and timeouts
212214
- Authentication method toggles (password, publickey, keyboard-interactive)
215+
- Public key authentication configuration (authorized_keys location)
213216

214217
- **SshHandler**: Per-connection handler for SSH protocol events
215-
- Authentication handling (placeholder implementations)
218+
- Public key authentication via AuthProvider trait
219+
- Rate limiting for authentication attempts
216220
- Channel operations (open, close, EOF, data)
217221
- PTY, exec, shell, and subsystem request handling
218222

@@ -221,7 +225,58 @@ SSH server implementation using the russh library for accepting incoming connect
221225
- Idle session management
222226
- Authentication state tracking
223227

224-
**Current Status**: Foundation implementation with placeholder authentication. Actual authentication and command execution will be implemented in follow-up issues (#126-#132).
228+
### Server Authentication Module
229+
230+
The authentication subsystem (`src/server/auth/`) provides extensible authentication for the SSH server:
231+
232+
**Structure**:
233+
- `mod.rs` - Module exports and re-exports
234+
- `provider.rs` - `AuthProvider` trait definition
235+
- `publickey.rs` - `PublicKeyVerifier` implementation
236+
237+
**AuthProvider Trait**:
238+
239+
The `AuthProvider` trait defines the interface for all authentication backends:
240+
241+
```rust
242+
#[async_trait]
243+
pub trait AuthProvider: Send + Sync {
244+
async fn verify_publickey(&self, username: &str, key: &PublicKey) -> Result<AuthResult>;
245+
async fn verify_password(&self, username: &str, password: &str) -> Result<AuthResult>;
246+
async fn get_user_info(&self, username: &str) -> Result<Option<UserInfo>>;
247+
async fn user_exists(&self, username: &str) -> Result<bool>;
248+
}
249+
```
250+
251+
**PublicKeyVerifier**:
252+
253+
Implements public key authentication by parsing OpenSSH authorized_keys files:
254+
255+
- **Key file location modes**:
256+
- Directory mode: `{dir}/{username}/authorized_keys`
257+
- Pattern mode: `/home/{user}/.ssh/authorized_keys`
258+
259+
- **Supported key types**:
260+
- ssh-ed25519, ssh-ed448
261+
- ssh-rsa, ssh-dss
262+
- ecdsa-sha2-nistp256/384/521
263+
- Security keys (sk-ssh-ed25519, sk-ecdsa-sha2-nistp256)
264+
265+
- **Key options parsing**:
266+
- `command="..."` - Force specific command
267+
- `from="..."` - Restrict source addresses
268+
- `no-pty`, `no-port-forwarding`, `no-agent-forwarding`, `no-X11-forwarding`
269+
- `environment="..."` - Set environment variables
270+
271+
**Security Features**:
272+
273+
- **Username validation**: Prevents path traversal attacks (e.g., `../etc/passwd`)
274+
- **File permission checks** (Unix): Rejects world/group-writable files and symlinks
275+
- **Symlink protection**: Uses `symlink_metadata()` to detect and reject symlinks
276+
- **Parent directory validation**: Checks parent directory permissions
277+
- **Rate limiting**: Token bucket rate limiter for authentication attempts
278+
- **Timing attack mitigation**: Constant-time behavior in `user_exists()` check
279+
- **Comprehensive logging**: All authentication attempts are logged
225280

226281
## Data Flow
227282

docs/architecture/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ bssh is a high-performance parallel SSH command execution tool with SSH-compatib
3333
### Server Components
3434

3535
- **SSH Server Module** - SSH server implementation using russh (see main ARCHITECTURE.md)
36+
- **Server Authentication** - Authentication providers including public key verification (see main ARCHITECTURE.md)
3637

3738
## Navigation
3839

src/server/auth/mod.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2025 Lablup Inc. and Jeongkyu Shin
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! Authentication provider infrastructure for bssh-server.
16+
//!
17+
//! This module provides the authentication framework for the SSH server,
18+
//! including traits for authentication providers and implementations for
19+
//! public key authentication.
20+
//!
21+
//! # Architecture
22+
//!
23+
//! The authentication system is designed around the [`AuthProvider`] trait,
24+
//! which allows for extensible authentication methods. Currently supported:
25+
//!
26+
//! - **Public Key Authentication**: Via [`PublicKeyVerifier`]
27+
//!
28+
//! # Security Features
29+
//!
30+
//! - Username validation to prevent path traversal attacks
31+
//! - Rate limiting integration
32+
//! - Logging of authentication attempts (success/failure)
33+
//! - Timing attack mitigation where possible
34+
//!
35+
//! # Usage
36+
//!
37+
//! ```no_run
38+
//! use bssh::server::auth::{AuthProvider, PublicKeyVerifier, PublicKeyAuthConfig};
39+
//! use std::path::PathBuf;
40+
//!
41+
//! // Create a public key verifier
42+
//! let config = PublicKeyAuthConfig::with_directory("/etc/bssh/authorized_keys");
43+
//! let verifier = PublicKeyVerifier::new(config);
44+
//!
45+
//! // Use with SSH handler
46+
//! // verifier.verify("username", &public_key).await
47+
//! ```
48+
49+
pub mod provider;
50+
pub mod publickey;
51+
52+
pub use provider::AuthProvider;
53+
pub use publickey::{AuthKeyOptions, AuthorizedKey, PublicKeyAuthConfig, PublicKeyVerifier};
54+
55+
// Re-export shared auth types for convenience
56+
pub use crate::shared::auth_types::{AuthResult, UserInfo};

0 commit comments

Comments
 (0)