인증/권한 업무 규칙과 전환 불변식 추출 #2
1 changed files with 163 additions and 0 deletions
163
auth-migration/INVARIANTS.md
Normal file
163
auth-migration/INVARIANTS.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Authentication & Authorization Transition Invariants
|
||||
|
||||
## 1. Authentication Rules
|
||||
|
||||
### 1.1 Login Flow
|
||||
|
||||
| Rule ID | Description | Invariant | Error Code |
|
||||
|---------|-------------|-----------|------------|
|
||||
| AUTH-001 | Username/password validation | Credentials must match stored hash; empty credentials rejected | `AUTH_001` |
|
||||
| AUTH-002 | Account lockout | 5 failed attempts → 15min lockout | `AUTH_002` |
|
||||
| AUTH-003 | Session creation | Valid JWT issued with 30min TTL | `AUTH_003` |
|
||||
| AUTH-004 | Password hashing | BCrypt with cost factor 12 | `AUTH_004` |
|
||||
|
||||
### 1.2 Token Management
|
||||
|
||||
| Rule ID | Description | Invariant | Error Code |
|
||||
|---------|-------------|-----------|------------|
|
||||
| AUTH-010 | JWT structure | `{sub, roles[], exp, iat}` claims required | `AUTH_010` |
|
||||
| AUTH-011 | Token refresh | Refresh token valid for 7 days, one-time use | `AUTH_011` |
|
||||
| AUTH-012 | Token revocation | Logout invalidates token immediately | `AUTH_012` |
|
||||
|
||||
### 1.3 MFA Rules
|
||||
|
||||
| Rule ID | Description | Invariant | Error Code |
|
||||
|---------|-------------|-----------|------------|
|
||||
| AUTH-020 | MFA required | TOTP 6-digit code, 30s window, ±1 drift | `AUTH_020` |
|
||||
| AUTH-021 | MFA bypass | Only for TRUSTED_DEVICE users | `AUTH_021` |
|
||||
|
||||
## 2. Authorization Rules
|
||||
|
||||
### 2.1 Role Hierarchy
|
||||
|
||||
| Rule ID | Description | Invariant | Error Code |
|
||||
|---------|-------------|-----------|------------|
|
||||
| AUTH-030 | Role precedence | ADMIN > MANAGER > USER > GUEST | `AUTH_030` |
|
||||
| AUTH-031 | Role assignment | Only ADMIN can assign roles | `AUTH_031` |
|
||||
| AUTH-032 | Self-demotion | ADMIN cannot demote own account | `AUTH_032` |
|
||||
|
||||
### 2.2 Permission Boundaries
|
||||
|
||||
| Rule ID | Description | Invariant | Error Code |
|
||||
|---------|-------------|-----------|------------|
|
||||
| AUTH-040 | Resource ownership | Users can only modify own resources | `AUTH_040` |
|
||||
| AUTH-041 | Cross-tenant access | No cross-tenant data access | `AUTH_041` |
|
||||
| AUTH-042 | Admin override | ADMIN bypasses ownership check | `AUTH_042` |
|
||||
|
||||
### 2.3 API Endpoint Permissions
|
||||
|
||||
| Rule ID | Endpoint Pattern | Required Role | Invariant |
|
||||
|---------|------------------|---------------|-----------|
|
||||
| AUTH-050 | `POST /auth/login` | GUEST | Public endpoint |
|
||||
| AUTH-051 | `POST /auth/logout` | USER+ | Authenticated |
|
||||
| AUTH-052 | `GET /admin/*` | ADMIN | Admin only |
|
||||
| AUTH-053 | `POST /users/*` | MANAGER+ | Manager+ only |
|
||||
| AUTH-054 | `GET /reports/*` | USER+ | Authenticated |
|
||||
|
||||
## 3. Error Response Format
|
||||
|
||||
### 3.1 Standard Error Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "AUTH_XXX",
|
||||
"message": "Human-readable message",
|
||||
"timestamp": "ISO-8601",
|
||||
"path": "/original/request/path"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 HTTP Status Mapping
|
||||
|
||||
| HTTP Status | Condition |
|
||||
|-------------|-----------|
|
||||
| 400 | Invalid request format |
|
||||
| 401 | Missing/invalid credentials |
|
||||
| 403 | Insufficient permissions |
|
||||
| 404 | Resource not found |
|
||||
| 423 | Account locked |
|
||||
| 429 | Rate limit exceeded |
|
||||
| 500 | Internal server error |
|
||||
|
||||
## 4. Security Invariants (Must Not Change)
|
||||
|
||||
| Priority | Invariant | Rationale |
|
||||
|----------|-----------|-----------|
|
||||
| CRITICAL | Passwords never logged | PII protection |
|
||||
| CRITICAL | Tokens never in URL query | Prevent log leakage |
|
||||
| CRITICAL | Session fixation prevention | CSRF protection |
|
||||
| HIGH | Rate limiting per IP | DoS prevention |
|
||||
| HIGH | Audit logging on auth events | Compliance |
|
||||
|
||||
## 5. Spring Migration Checklist
|
||||
|
||||
- [ ] SecurityConfig with BCryptPasswordEncoder bean
|
||||
- [ ] JwtAuthenticationFilter ordering (before UsernamePasswordAuthenticationFilter)
|
||||
- [ ] @EnableMethodSecurity for @PreAuthorize annotations
|
||||
- [ ] Custom AuthenticationEntryPoint for error responses
|
||||
- [ ] Custom AccessDeniedHandler for 403 responses
|
||||
- [ ] SessionManagement with fixed session fixation protection
|
||||
- [ ] CORS configuration aligned with existing origins
|
||||
|
||||
## 6. Implementation Reference
|
||||
|
||||
### 6.1 SecurityConfig Bean Configuration
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder(12); // AUTH-004
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.csrf(csrf -> csrf
|
||||
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
|
||||
.ignoringRequestMatchers("/auth/login", "/auth/refresh")
|
||||
)
|
||||
.sessionManagement(s -> s
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.sessionFixation().migrateSession()
|
||||
)
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/auth/login", "/auth/refresh").permitAll()
|
||||
.requestMatchers("/admin/**").hasRole("ADMIN")
|
||||
.requestMatchers("/users/**").hasAnyRole("MANAGER", "ADMIN")
|
||||
.requestMatchers("/reports/**").authenticated()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.exceptionHandling(ex -> ex
|
||||
.authenticationEntryPoint(new CustomAuthEntryPoint())
|
||||
.accessDeniedHandler(new CustomAccessDeniedHandler())
|
||||
)
|
||||
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 JWT Claims Structure
|
||||
|
||||
```java
|
||||
public record JwtClaims(
|
||||
String subject, // username
|
||||
List<String> roles, // ["ADMIN", "USER"]
|
||||
Date issuedAt,
|
||||
Date expiration // 30min for access, 7days for refresh
|
||||
) {}
|
||||
```
|
||||
|
||||
### 6.3 Lockout Logic
|
||||
|
||||
```java
|
||||
private static final int MAX_FAILED_ATTEMPTS = 5;
|
||||
private static final long LOCKOUT_DURATION_MS = 15 * 60 * 1000;
|
||||
```
|
||||
|
||||
### 6.4 Role Hierarchy Levels
|
||||
|
||||
```java
|
||||
private static final List<String> ROLE_HIERARCHY =
|
||||
List.of("ADMIN", "MANAGER", "USER", "GUEST");
|
||||
// Lower index = higher privilege
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue