summaryrefslogtreecommitdiff
path: root/REFACTORING_PLAN.md
blob: ec244498895247f7dded872e793b0c7b59bd1562 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
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<String, String>,
        auth_header: Option<&str>,
        ip_address: Option<String>,
    ) -> Result<String, String>;
}

struct AuthorizationCodeGrantHandler {
    client_authenticator: Arc<dyn ClientAuthenticator>,
    token_generator: Arc<dyn TokenGenerator>,
    code_repository: Arc<dyn AuthCodeRepository>,
    token_repository: Arc<dyn TokenRepository>,
    audit_logger: Arc<dyn AuditLogger>,
}

struct RefreshTokenGrantHandler {
    // Similar dependencies
}

struct GrantHandlerRegistry {
    handlers: Vec<Arc<dyn GrantHandler>>,
}
```

### 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<Option<OAuthClient>>;
    fn authenticate_client(&self, client_id: &str, secret: &str) -> Result<bool>;
    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<Option<DbAccessToken>>;
    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<Option<DbAuthCode>>;
    fn mark_auth_code_used(&self, code: &str) -> Result<()>;
}

// SQLite implementations
struct SqliteClientRepository {
    database: Arc<Mutex<Database>>,
}

struct SqliteTokenRepository {
    database: Arc<Mutex<Database>>,
}
```

### 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<String, String>,
        auth_header: Option<&str>,
    ) -> Result<(String, String), String>; // Returns (client_id, client_secret)
}

struct BasicAuthenticator {
    client_repository: Arc<dyn ClientRepository>,
}

struct PostAuthenticator {
    client_repository: Arc<dyn ClientRepository>,
}

struct CompositeAuthenticator {
    authenticators: Vec<Arc<dyn ClientAuthenticator>>,
}
```

### 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<String>,
        token_id: &str,
    ) -> Result<String>;
    
    fn generate_refresh_token(
        &self,
        client_id: &str,
        user_id: &str,
        scope: &Option<String>,
    ) -> Result<String>;
}

struct JwtTokenGenerator {
    key_manager: Arc<Mutex<KeyManager>>,
    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<dyn RateRepository>,
    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<dyn AuditRepository>,
}

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<OAuthHandler>,
    static_handler: Arc<StaticHandler>,
}

struct OAuthHandler {
    oauth_service: Arc<OAuthService>, // 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<dyn ClientRepository>,
    token_repository: Arc<dyn TokenRepository>,
    auth_code_repository: Arc<dyn AuthCodeRepository>,
    
    // Services
    client_authenticator: Arc<dyn ClientAuthenticator>,
    token_generator: Arc<dyn TokenGenerator>,
    rate_limiter: Arc<dyn RateLimiter>,
    audit_logger: Arc<dyn AuditLogger>,
    
    // Grant handlers
    grant_registry: Arc<GrantHandlerRegistry>,
}

impl ServiceContainer {
    fn new(config: &Config) -> Result<Self> {
        // 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