From 5ffc9b007ccbd8a4510b58de72aaee53291d7973 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 11 Jun 2025 17:11:39 -0600 Subject: refactor: apply SOLID principles --- REFACTORING_PLAN.md | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 REFACTORING_PLAN.md (limited to 'REFACTORING_PLAN.md') diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md new file mode 100644 index 0000000..ec24449 --- /dev/null +++ b/REFACTORING_PLAN.md @@ -0,0 +1,289 @@ +# OAuth2 STS SOLID Refactoring Plan + +## Overview +This document outlines refactoring opportunities to better align with SOLID principles. + +## 1. Extract Grant Type Handlers (SRP + OCP) + +### Current Issue +`OAuthServer::handle_token()` contains all grant type logic in one method. + +### Proposed Solution +```rust +trait GrantHandler { + fn can_handle(&self, grant_type: &str) -> bool; + fn handle_grant( + &self, + params: &HashMap, + auth_header: Option<&str>, + ip_address: Option, + ) -> Result; +} + +struct AuthorizationCodeGrantHandler { + client_authenticator: Arc, + token_generator: Arc, + code_repository: Arc, + token_repository: Arc, + audit_logger: Arc, +} + +struct RefreshTokenGrantHandler { + // Similar dependencies +} + +struct GrantHandlerRegistry { + handlers: Vec>, +} +``` + +### Benefits +- ✅ Easy to add new grant types (Client Credentials, Device Code, etc.) +- ✅ Each handler has single responsibility +- ✅ Testable in isolation + +## 2. Create Repository Abstractions (DIP + SRP) + +### Current Issue +Monolithic `Database` struct violates SRP and makes testing difficult. + +### Proposed Solution +```rust +trait ClientRepository { + fn get_client(&self, client_id: &str) -> Result>; + fn authenticate_client(&self, client_id: &str, secret: &str) -> Result; + fn is_redirect_uri_valid(&self, client_id: &str, uri: &str) -> bool; +} + +trait TokenRepository { + fn create_access_token(&self, token: &DbAccessToken) -> Result<()>; + fn get_access_token(&self, token_hash: &str) -> Result>; + fn revoke_access_token(&self, token_hash: &str) -> Result<()>; +} + +trait AuthCodeRepository { + fn create_auth_code(&self, code: &DbAuthCode) -> Result<()>; + fn get_auth_code(&self, code: &str) -> Result>; + fn mark_auth_code_used(&self, code: &str) -> Result<()>; +} + +// SQLite implementations +struct SqliteClientRepository { + database: Arc>, +} + +struct SqliteTokenRepository { + database: Arc>, +} +``` + +### Benefits +- ✅ Easy to swap database backends (PostgreSQL, Redis, etc.) +- ✅ Better testability with mock repositories +- ✅ Clear separation of concerns + +## 3. Extract Authentication Strategy (OCP + SRP) + +### Current Issue +Client authentication logic scattered throughout token handlers. + +### Proposed Solution +```rust +trait ClientAuthenticator { + fn authenticate( + &self, + params: &HashMap, + auth_header: Option<&str>, + ) -> Result<(String, String), String>; // Returns (client_id, client_secret) +} + +struct BasicAuthenticator { + client_repository: Arc, +} + +struct PostAuthenticator { + client_repository: Arc, +} + +struct CompositeAuthenticator { + authenticators: Vec>, +} +``` + +### Benefits +- ✅ Easy to add new authentication methods (JWT, mTLS, etc.) +- ✅ Clear separation of authentication concerns +- ✅ Configurable authentication strategies + +## 4. Extract Token Generation (SRP + OCP) + +### Current Issue +Token generation logic embedded in `OAuthServer`. + +### Proposed Solution +```rust +trait TokenGenerator { + fn generate_access_token( + &self, + user_id: &str, + client_id: &str, + scope: &Option, + token_id: &str, + ) -> Result; + + fn generate_refresh_token( + &self, + client_id: &str, + user_id: &str, + scope: &Option, + ) -> Result; +} + +struct JwtTokenGenerator { + key_manager: Arc>, + config: Config, +} + +struct OpaqueTokenGenerator { + // For opaque token implementation +} +``` + +### Benefits +- ✅ Easy to switch token formats (JWT vs opaque) +- ✅ Configurable token generation strategies +- ✅ Better testability + +## 5. Extract Cross-Cutting Concerns + +### Rate Limiting +```rust +trait RateLimiter { + fn check_rate_limit(&self, identifier: &str, endpoint: &str) -> Result<()>; +} + +struct DatabaseRateLimiter { + rate_repository: Arc, + config: Config, +} + +struct RedisRateLimiter { + redis_client: redis::Client, + config: Config, +} +``` + +### Audit Logging +```rust +trait AuditLogger { + fn log_event(&self, event: AuditEvent) -> Result<()>; +} + +struct DatabaseAuditLogger { + audit_repository: Arc, +} + +struct JsonFileAuditLogger { + file_path: PathBuf, +} +``` + +## 6. Refactor HTTP Layer (SRP) + +### Current Issue +`Server` mixes HTTP protocol with OAuth business logic. + +### Proposed Solution +```rust +struct HttpServer { + router: Router, + config: Config, +} + +struct Router { + oauth_handler: Arc, + static_handler: Arc, +} + +struct OAuthHandler { + oauth_service: Arc, // Renamed from OAuthServer +} + +// Clean separation between HTTP concerns and OAuth business logic +``` + +## 7. Dependency Injection Container + +### Proposed Solution +```rust +struct ServiceContainer { + // Repositories + client_repository: Arc, + token_repository: Arc, + auth_code_repository: Arc, + + // Services + client_authenticator: Arc, + token_generator: Arc, + rate_limiter: Arc, + audit_logger: Arc, + + // Grant handlers + grant_registry: Arc, +} + +impl ServiceContainer { + fn new(config: &Config) -> Result { + // Wire up all dependencies + } +} +``` + +## Implementation Strategy + +### Phase 1: Repository Extraction +1. Create repository traits +2. Move database methods to specific repositories +3. Update `OAuthServer` to use repositories + +### Phase 2: Grant Handler Extraction +1. Create `GrantHandler` trait +2. Extract authorization code handler +3. Extract refresh token handler +4. Create registry + +### Phase 3: Cross-Cutting Concerns +1. Extract rate limiting +2. Extract audit logging +3. Extract authentication + +### Phase 4: HTTP Layer Cleanup +1. Separate HTTP protocol from business logic +2. Create clean request/response handlers + +### Phase 5: Dependency Injection +1. Create service container +2. Wire up all dependencies +3. Update main.rs to use container + +## Benefits of This Refactoring + +### Maintainability +- ✅ Easier to understand and modify individual components +- ✅ Clear separation of concerns +- ✅ Reduced coupling between components + +### Extensibility +- ✅ Easy to add new grant types +- ✅ Easy to swap implementations (database, token format, etc.) +- ✅ Configurable strategies for cross-cutting concerns + +### Testability +- ✅ Each component can be tested in isolation +- ✅ Easy to create mock implementations +- ✅ Better unit test coverage + +### Production Readiness +- ✅ Easy to scale different components independently +- ✅ Better observability and monitoring capabilities +- ✅ More flexible deployment options \ No newline at end of file -- cgit v1.2.3