omniauth_openid_federation 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.md +22 -0
  4. data/README.md +822 -0
  5. data/SECURITY.md +129 -0
  6. data/examples/README_INTEGRATION_TESTING.md +399 -0
  7. data/examples/README_MOCK_OP.md +243 -0
  8. data/examples/app/controllers/users/omniauth_callbacks_controller.rb.example +33 -0
  9. data/examples/app/jobs/jwks_rotation_job.rb.example +60 -0
  10. data/examples/app/models/user.rb.example +39 -0
  11. data/examples/config/initializers/devise.rb.example +97 -0
  12. data/examples/config/initializers/federation_endpoint.rb.example +206 -0
  13. data/examples/config/mock_op.yml.example +83 -0
  14. data/examples/config/open_id_connect_config.rb.example +210 -0
  15. data/examples/config/routes.rb.example +12 -0
  16. data/examples/db/migrate/add_omniauth_to_users.rb.example +16 -0
  17. data/examples/integration_test_flow.rb +1334 -0
  18. data/examples/jobs/README.md +194 -0
  19. data/examples/jobs/federation_cache_refresh_job.rb.example +78 -0
  20. data/examples/jobs/federation_files_generation_job.rb.example +87 -0
  21. data/examples/mock_op_server.rb +775 -0
  22. data/examples/mock_rp_server.rb +435 -0
  23. data/lib/omniauth_openid_federation/access_token.rb +504 -0
  24. data/lib/omniauth_openid_federation/cache.rb +39 -0
  25. data/lib/omniauth_openid_federation/cache_adapter.rb +173 -0
  26. data/lib/omniauth_openid_federation/configuration.rb +135 -0
  27. data/lib/omniauth_openid_federation/constants.rb +13 -0
  28. data/lib/omniauth_openid_federation/endpoint_resolver.rb +168 -0
  29. data/lib/omniauth_openid_federation/entity_statement_reader.rb +122 -0
  30. data/lib/omniauth_openid_federation/errors.rb +52 -0
  31. data/lib/omniauth_openid_federation/federation/entity_statement.rb +331 -0
  32. data/lib/omniauth_openid_federation/federation/entity_statement_builder.rb +188 -0
  33. data/lib/omniauth_openid_federation/federation/entity_statement_fetcher.rb +142 -0
  34. data/lib/omniauth_openid_federation/federation/entity_statement_helper.rb +87 -0
  35. data/lib/omniauth_openid_federation/federation/entity_statement_parser.rb +198 -0
  36. data/lib/omniauth_openid_federation/federation/entity_statement_validator.rb +502 -0
  37. data/lib/omniauth_openid_federation/federation/metadata_policy_merger.rb +276 -0
  38. data/lib/omniauth_openid_federation/federation/signed_jwks.rb +210 -0
  39. data/lib/omniauth_openid_federation/federation/trust_chain_resolver.rb +225 -0
  40. data/lib/omniauth_openid_federation/federation_endpoint.rb +949 -0
  41. data/lib/omniauth_openid_federation/http_client.rb +70 -0
  42. data/lib/omniauth_openid_federation/instrumentation.rb +383 -0
  43. data/lib/omniauth_openid_federation/jwks/cache.rb +76 -0
  44. data/lib/omniauth_openid_federation/jwks/decode.rb +174 -0
  45. data/lib/omniauth_openid_federation/jwks/fetch.rb +153 -0
  46. data/lib/omniauth_openid_federation/jwks/normalizer.rb +49 -0
  47. data/lib/omniauth_openid_federation/jwks/rotate.rb +97 -0
  48. data/lib/omniauth_openid_federation/jwks/selector.rb +101 -0
  49. data/lib/omniauth_openid_federation/jws.rb +416 -0
  50. data/lib/omniauth_openid_federation/key_extractor.rb +173 -0
  51. data/lib/omniauth_openid_federation/logger.rb +99 -0
  52. data/lib/omniauth_openid_federation/rack_endpoint.rb +187 -0
  53. data/lib/omniauth_openid_federation/railtie.rb +29 -0
  54. data/lib/omniauth_openid_federation/rate_limiter.rb +55 -0
  55. data/lib/omniauth_openid_federation/strategy.rb +2029 -0
  56. data/lib/omniauth_openid_federation/string_helpers.rb +30 -0
  57. data/lib/omniauth_openid_federation/tasks_helper.rb +428 -0
  58. data/lib/omniauth_openid_federation/utils.rb +166 -0
  59. data/lib/omniauth_openid_federation/validators.rb +126 -0
  60. data/lib/omniauth_openid_federation/version.rb +3 -0
  61. data/lib/omniauth_openid_federation.rb +98 -0
  62. data/lib/tasks/omniauth_openid_federation.rake +376 -0
  63. data/sig/federation.rbs +218 -0
  64. data/sig/jwks.rbs +63 -0
  65. data/sig/omniauth_openid_federation.rbs +254 -0
  66. data/sig/strategy.rbs +60 -0
  67. metadata +352 -0
data/SECURITY.md ADDED
@@ -0,0 +1,129 @@
1
+ # SECURITY
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ **Do NOT** open a public GitHub issue for security vulnerabilities.
6
+
7
+ Email security details to: **contact@kiskolabs.com**
8
+
9
+ Include: description, steps to reproduce, potential impact, and suggested fix (if available).
10
+
11
+ **Response Timeline:**
12
+ - Acknowledgment within 48 hours
13
+ - Initial assessment within 7 days
14
+ - Coordinated disclosure after patching
15
+
16
+ ## Library Security Features
17
+
18
+ ### Implemented Protections
19
+
20
+ **✅ Constant-Time State Comparison**
21
+ - Uses `Rack::Utils.secure_compare` for state parameter validation to prevent timing attacks
22
+ - Location: `strategy.rb:182`
23
+
24
+ **✅ Path Traversal Protection**
25
+ - `Utils.validate_file_path!` prevents `..` sequences and validates against allowed directories
26
+ - File paths are restricted to configured allowed directories
27
+
28
+ **✅ Signed Request Objects (RFC 9101)**
29
+ - All authorization requests **MUST** use signed request objects (mandatory per OpenID Federation 1.0 spec)
30
+ - Signing is enforced at library level - cannot be bypassed
31
+ - Request objects **MAY** be encrypted (optional) when provider requires it or `always_encrypt_request_object` is enabled
32
+ - Prevents parameter tampering and ensures request authenticity
33
+
34
+ **✅ JWT Algorithm Validation**
35
+ - JWT library validates algorithms and signatures
36
+ - Unsigned tokens (`alg: none`) are explicitly handled and rejected for signed tokens
37
+ - Only strong algorithms accepted (RS256, etc.)
38
+
39
+ **✅ Logging Sanitization**
40
+ - Sensitive data (tokens, keys) is never logged
41
+ - File paths are sanitized before logging
42
+ - URLs are sanitized (query parameters removed) in debug logs
43
+
44
+ **✅ Timeout Limits**
45
+ - HTTP requests have configurable timeouts to prevent long-running requests
46
+
47
+ ### Known Limitations & Risks
48
+
49
+ **⚠️ SSRF Risk (Server-Side Request Forgery)**
50
+ - The library fetches entity statements and JWKS from URLs without validating against internal network access
51
+ - **Risk:** URLs could target localhost, private IPs, or cloud metadata endpoints
52
+ - **Mitigation:** Application should validate URLs before passing to library, or implement URL validation in library configuration
53
+
54
+ **⚠️ Memory Safety**
55
+ - Ruby does not provide secure memory management for sensitive data
56
+ - Private keys may persist in memory until garbage collection
57
+ - Memory dumps may contain key material
58
+ - **Mitigation:** Use secure environments and access controls
59
+
60
+ **⚠️ SSL/TLS Verification**
61
+ - SSL verification is automatically disabled in Rails development mode
62
+ - **Production:** Application must ensure SSL verification is enabled
63
+
64
+ **⚠️ Entity Statement Validation**
65
+ - Fingerprint validation is optional - skipping validation may allow malicious entity statements
66
+ - **Recommendation:** Always validate entity statement fingerprints when fetching from untrusted sources
67
+
68
+ **⚠️ Key Rotation Window**
69
+ - Brief window (up to cache TTL, default 24 hours) where rotated keys might not be immediately available
70
+ - Library handles this with retry logic, but applications should monitor rotation events
71
+
72
+ ## Input/Output Points
73
+
74
+ ### Input Points (Library Handles)
75
+
76
+ 1. **OAuth Callback Parameters** (`code`, `state`, `error`)
77
+ - State validated with constant-time comparison
78
+ - Authorization codes are single-use and time-limited
79
+
80
+ 2. **OAuth Request Parameters** (`acr_values`, `login_hint`, etc.)
81
+ - All parameters are signed in JWT request objects (RFC 9101)
82
+ - Parameters validated before inclusion
83
+
84
+ 3. **Entity Statement URLs**
85
+ - Fetched via HTTP client
86
+ - **SSRF Risk:** No validation against internal network access
87
+
88
+ 4. **File Paths** (configuration)
89
+ - Validated with `Utils.validate_file_path!` to prevent path traversal
90
+ - Restricted to allowed directories
91
+
92
+ 5. **JWT/JWE Tokens** (from OAuth provider)
93
+ - Algorithm validation enforced
94
+ - Signature validation required for signed tokens
95
+ - Entity statement fingerprints provide additional validation
96
+
97
+ ### Output Points (Library Exposes)
98
+
99
+ 1. **HTTP Responses** (if using `RackEndpoint`)
100
+ - `/.well-known/openid-federation` - Entity statement (JWT)
101
+ - `/.well-known/jwks.json` - Public JWKS
102
+ - `/.well-known/signed-jwks.json` - Signed JWKS (JWT)
103
+ - Only public keys exposed (private keys never exposed)
104
+
105
+ 2. **Logs**
106
+ - Sensitive data (tokens, keys) never logged
107
+ - File paths and URLs sanitized before logging
108
+
109
+ 3. **Error Messages**
110
+ - File paths sanitized in error messages
111
+ - Generic error messages (stack traces only in development)
112
+
113
+ ## Security Considerations
114
+
115
+ - **Timing Attacks**: State parameter protected with constant-time comparison
116
+ - **Path Traversal**: ✅ `Utils.validate_file_path!` prevents `..` sequences
117
+ - **JWT Algorithm Confusion**: ✅ Algorithm validation enforced, `alg: none` rejected
118
+ - **Replay Attacks**: Authorization codes are single-use and time-limited
119
+
120
+ ## Automation Security
121
+
122
+ * **Context Isolation:** It is strictly forbidden to include production credentials, API keys, or Personally Identifiable Information (PII) in prompts sent to third-party LLMs or automation services.
123
+
124
+ * **Supply Chain:** All automated dependencies must be verified.
125
+
126
+ ## Contact
127
+
128
+ **Security concerns**: contact@kiskolabs.com
129
+ **General support**: https://github.com/amkisko/omniauth_openid_federation.rb/issues
@@ -0,0 +1,399 @@
1
+ # OpenID Federation Integration Testing
2
+
3
+ This directory contains comprehensive mock servers and integration tests for the complete OpenID Federation flow.
4
+
5
+ ## Architecture
6
+
7
+ The integration test setup consists of:
8
+
9
+ 1. **Mock OP Server** (`mock_op_server.rb`) - Simulates an OpenID Provider
10
+ 2. **Mock RP Server** (`mock_rp_server.rb`) - Simulates a Relying Party (Client)
11
+ 3. **Integration Test Flow** (`integration_test_flow.rb`) - Automated tests for the complete flow
12
+
13
+ ## Complete OpenID Federation Flow
14
+
15
+ ### 1. Provider Exposes Entity Statement with JWKS
16
+
17
+ The OP server exposes its entity configuration at:
18
+ ```
19
+ GET /.well-known/openid-federation
20
+ ```
21
+
22
+ Returns a signed JWT containing:
23
+ - Provider metadata (authorization_endpoint, token_endpoint, etc.)
24
+ - JWKS (public keys for signing/encryption)
25
+ - Authority hints (if subordinate to a Trust Anchor)
26
+
27
+ ### 2. Client Exposes Entity Statement with JWKS
28
+
29
+ The RP server exposes its entity configuration at:
30
+ ```
31
+ GET /.well-known/openid-federation
32
+ ```
33
+
34
+ Returns a signed JWT containing:
35
+ - RP metadata (redirect_uris, client_name, etc.)
36
+ - JWKS (public keys for signing request objects)
37
+ - Authority hints (if subordinate to a Trust Anchor)
38
+
39
+ ### 3. Client Fetches Provider Statement with Keys
40
+
41
+ When the RP initiates login:
42
+ 1. RP fetches OP's entity statement from `/.well-known/openid-federation`
43
+ 2. RP validates the entity statement signature
44
+ 3. RP extracts OP's JWKS for future token validation
45
+ 4. RP extracts OP's metadata (endpoints, capabilities)
46
+
47
+ ### 4. Client Sends Login Request
48
+
49
+ RP generates a signed request object (JWT) containing:
50
+ - `client_id`: RP's Entity ID
51
+ - `redirect_uri`: Callback URL
52
+ - `scope`: Requested scopes
53
+ - `state`: CSRF protection
54
+ - `nonce`: Replay protection
55
+ - `aud`: OP's Entity ID
56
+
57
+ The request object is:
58
+ - **Always signed** with RP's private key (RFC 9101 requirement)
59
+ - **Optionally encrypted** if OP requires encryption
60
+
61
+ RP redirects to OP's authorization endpoint:
62
+ ```
63
+ GET /auth?request=<signed_jwt>
64
+ ```
65
+
66
+ ### 5. Provider Fetches Client Statement and Keys
67
+
68
+ When OP receives the authorization request:
69
+ 1. OP extracts `client_id` from the request object
70
+ 2. OP fetches RP's entity statement from `/.well-known/openid-federation`
71
+ 3. OP validates RP's entity statement signature
72
+ 4. OP extracts RP's JWKS from the entity statement
73
+ 5. OP validates the request object signature using RP's public key
74
+ 6. OP resolves RP's trust chain (if trust anchors configured)
75
+ 7. OP applies metadata policies from trust chain
76
+ 8. OP validates `redirect_uri` against RP's allowed redirect URIs
77
+
78
+ ### 6. Exchange and Authenticated Login
79
+
80
+ After user authorization:
81
+ 1. OP redirects back to RP with authorization code
82
+ 2. RP exchanges code for tokens at OP's token endpoint
83
+ 3. OP returns ID token (signed with OP's private key)
84
+ 4. RP validates ID token signature using OP's JWKS
85
+ 5. RP validates ID token claims (iss, aud, exp, nonce)
86
+ 6. User is authenticated
87
+
88
+ ## Error Scenarios Supported
89
+
90
+ The mock servers support error injection via `?error_mode=<mode>` parameter:
91
+
92
+ ### Invalid Statement
93
+ ```
94
+ GET /.well-known/openid-federation?error_mode=invalid_statement
95
+ ```
96
+ Returns malformed JWT to test error handling.
97
+
98
+ ### Wrong Keys
99
+ ```
100
+ GET /.well-known/jwks.json?error_mode=wrong_keys
101
+ GET /.well-known/openid-federation?error_mode=wrong_keys
102
+ ```
103
+ Returns JWKS with keys that don't match the signing key.
104
+
105
+ ### Invalid Request
106
+ ```
107
+ GET /auth?error_mode=invalid_request
108
+ ```
109
+ Rejects request object validation to test error handling.
110
+
111
+ ### Invalid Signature
112
+ ```
113
+ GET /.well-known/signed-jwks.json?error_mode=invalid_signature
114
+ ```
115
+ Returns signed JWKS with invalid signature.
116
+
117
+ ### Expired Statement
118
+ ```
119
+ GET /.well-known/openid-federation?error_mode=expired_statement
120
+ ```
121
+ Returns expired entity statement to test expiration handling.
122
+
123
+ ### Missing Metadata
124
+ ```
125
+ GET /.well-known/openid-federation?error_mode=missing_metadata
126
+ ```
127
+ Returns entity statement without metadata to test validation.
128
+
129
+ ## Usage
130
+
131
+ ### Quick Start (Automated - Recommended)
132
+
133
+ The integration test flow can automatically start servers, generate keys, and run all tests:
134
+
135
+ ```bash
136
+ # Single command - fully automated
137
+ ruby examples/integration_test_flow.rb
138
+ ```
139
+
140
+ This will:
141
+ 1. Create temporary directories for keys and configs
142
+ 2. Generate RSA keys for both OP and RP (using rake task logic)
143
+ 3. Configure and start both servers automatically
144
+ 4. Wait for servers to be ready
145
+ 5. Run all integration tests
146
+ 6. Clean up (kill servers, remove tmp dirs) on exit
147
+
148
+ ### Manual Start (For Debugging)
149
+
150
+ If you want to start servers manually for debugging:
151
+
152
+ **Terminal 1 - OP Server:**
153
+ ```bash
154
+ ruby examples/mock_op_server.rb
155
+ # Server runs on http://localhost:9292
156
+ ```
157
+
158
+ **Terminal 2 - RP Server:**
159
+ ```bash
160
+ ruby examples/mock_rp_server.rb
161
+ # Server runs on http://localhost:9293
162
+ ```
163
+
164
+ **Terminal 3 - Integration Tests:**
165
+ ```bash
166
+ # Disable auto-start to use manually started servers
167
+ AUTO_START_SERVERS=false ruby examples/integration_test_flow.rb
168
+ ```
169
+
170
+ ### Environment Variables
171
+
172
+ The integration test flow supports the following environment variables:
173
+
174
+ ```bash
175
+ # Server URLs
176
+ OP_URL=http://localhost:9292 # OP server URL
177
+ RP_URL=http://localhost:9293 # RP server URL
178
+
179
+ # Server Ports
180
+ OP_PORT=9292 # OP server port
181
+ RP_PORT=9293 # RP server port
182
+
183
+ # Entity IDs
184
+ OP_ENTITY_ID=https://op.example.com # OP entity identifier
185
+ RP_ENTITY_ID=https://rp.example.com # RP entity identifier
186
+
187
+ # Temporary Directory
188
+ TMP_DIR=tmp/integration_test # Directory for keys/configs (default: tmp/integration_test)
189
+
190
+ # Auto-start servers (true/false)
191
+ AUTO_START_SERVERS=true # Auto-start servers (default: true)
192
+
193
+ # Cleanup on exit (true/false)
194
+ CLEANUP_ON_EXIT=true # Clean up tmp dirs on exit (default: true)
195
+
196
+ # Key Type
197
+ KEY_TYPE=separate # 'single' or 'separate' (default: separate)
198
+ ```
199
+
200
+ **Example with custom configuration:**
201
+ ```bash
202
+ KEY_TYPE=separate \
203
+ TMP_DIR=/tmp/my_test \
204
+ ruby examples/integration_test_flow.rb
205
+ ```
206
+
207
+ **Note**: By default, the integration test uses localhost URLs for complete isolation:
208
+ - No DNS resolution required
209
+ - No external network dependencies
210
+ - All communication happens on localhost
211
+ - Entity IDs default to `http://localhost:9292` (OP) and `http://localhost:9293` (RP)
212
+
213
+ This ensures the tests work in any environment without network configuration.
214
+
215
+ ### Manual Testing
216
+
217
+ **1. Test Provider Entity Statement:**
218
+ ```bash
219
+ curl http://localhost:9292/.well-known/openid-federation
220
+ ```
221
+
222
+ **2. Test Client Entity Statement:**
223
+ ```bash
224
+ curl http://localhost:9293/.well-known/openid-federation
225
+ ```
226
+
227
+ **3. Test Login Flow:**
228
+ ```bash
229
+ # Initiate login (will redirect to OP)
230
+ curl -L "http://localhost:9293/login?provider=https://op.example.com"
231
+ ```
232
+
233
+ **4. Test Error Scenarios:**
234
+ ```bash
235
+ # Invalid statement
236
+ curl "http://localhost:9292/.well-known/openid-federation?error_mode=invalid_statement"
237
+
238
+ # Wrong keys
239
+ curl "http://localhost:9292/.well-known/jwks.json?error_mode=wrong_keys"
240
+
241
+ # Expired statement
242
+ curl "http://localhost:9292/.well-known/openid-federation?error_mode=expired_statement"
243
+ ```
244
+
245
+ ## Configuration
246
+
247
+ ### OP Server Configuration
248
+
249
+ Create `examples/config/mock_op.yml`:
250
+
251
+ ```yaml
252
+ entity_id: "https://op.example.com"
253
+ server_host: "localhost:9292"
254
+ signing_key: |
255
+ -----BEGIN RSA PRIVATE KEY-----
256
+ ...
257
+ -----END RSA PRIVATE KEY-----
258
+ encryption_key: | # Optional, defaults to signing_key
259
+ -----BEGIN RSA PRIVATE KEY-----
260
+ ...
261
+ -----END RSA PRIVATE KEY-----
262
+ trust_anchors:
263
+ - entity_id: "https://ta.example.com"
264
+ jwks:
265
+ keys:
266
+ - kty: "RSA"
267
+ kid: "ta-key-1"
268
+ use: "sig"
269
+ n: "..."
270
+ e: "AQAB"
271
+ authority_hints: # Optional, if OP is subordinate
272
+ - "https://ta.example.com"
273
+ op_metadata:
274
+ issuer: "https://op.example.com"
275
+ authorization_endpoint: "https://op.example.com/auth"
276
+ token_endpoint: "https://op.example.com/token"
277
+ request_object_encryption_alg_values_supported: ["RSA-OAEP"]
278
+ request_object_encryption_enc_values_supported: ["A128CBC-HS256"]
279
+ require_request_encryption: false # Set to true to require encryption
280
+ validate_request_objects: true # Set to false to skip validation
281
+ ```
282
+
283
+ ### RP Server Configuration
284
+
285
+ Create `examples/config/mock_rp.yml`:
286
+
287
+ ```yaml
288
+ entity_id: "https://rp.example.com"
289
+ server_host: "localhost:9293"
290
+ signing_key: |
291
+ -----BEGIN RSA PRIVATE KEY-----
292
+ ...
293
+ -----END RSA PRIVATE KEY-----
294
+ encryption_key: | # Optional, for decrypting encrypted ID tokens
295
+ -----BEGIN RSA PRIVATE KEY-----
296
+ ...
297
+ -----END RSA PRIVATE KEY-----
298
+ trust_anchors:
299
+ - entity_id: "https://ta.example.com"
300
+ jwks:
301
+ keys: [...]
302
+ authority_hints: # Optional, if RP is subordinate
303
+ - "https://ta.example.com"
304
+ redirect_uris:
305
+ - "https://rp.example.com/callback"
306
+ ```
307
+
308
+ ## Testing Scenarios
309
+
310
+ ### Happy Path
311
+
312
+ 1. Start both servers
313
+ 2. Run integration tests: `ruby examples/integration_test_flow.rb`
314
+ 3. All tests should pass
315
+
316
+ ### Error Scenarios
317
+
318
+ 1. Test invalid entity statement:
319
+ ```bash
320
+ curl "http://localhost:9292/.well-known/openid-federation?error_mode=invalid_statement"
321
+ ```
322
+
323
+ 2. Test wrong keys:
324
+ ```bash
325
+ curl "http://localhost:9292/.well-known/jwks.json?error_mode=wrong_keys"
326
+ ```
327
+
328
+ 3. Test expired statement:
329
+ ```bash
330
+ curl "http://localhost:9292/.well-known/openid-federation?error_mode=expired_statement"
331
+ ```
332
+
333
+ ### Request Object Validation
334
+
335
+ 1. Test with valid signed request object:
336
+ ```bash
337
+ curl "http://localhost:9293/login?provider=https://op.example.com"
338
+ ```
339
+
340
+ 2. Test with invalid request object:
341
+ ```bash
342
+ curl "http://localhost:9292/auth?error_mode=invalid_request&request=invalid.jwt"
343
+ ```
344
+
345
+ ### Trust Chain Resolution
346
+
347
+ 1. Configure trust anchors in both servers
348
+ 2. Ensure RP has authority_hints pointing to trust anchor
349
+ 3. OP will resolve RP's trust chain during authorization
350
+ 4. OP will apply metadata policies from trust chain
351
+
352
+ ## Security Testing
353
+
354
+ The mock servers support comprehensive security testing:
355
+
356
+ - **Algorithm Confusion**: Test rejection of non-RS256 algorithms
357
+ - **Key Confusion**: Test rejection of wrong keys
358
+ - **Signature Verification**: Test rejection of tampered signatures
359
+ - **Path Traversal**: Test rejection of malicious paths
360
+ - **Replay Attacks**: Test nonce validation
361
+ - **Request Object Validation**: Test signature and encryption validation
362
+ - **Trust Chain Validation**: Test authority hints and metadata policy enforcement
363
+
364
+ ## Troubleshooting
365
+
366
+ ### Server Won't Start
367
+
368
+ - Check if ports 9292 (OP) and 9293 (RP) are available
369
+ - Verify all dependencies are installed: `bundle install`
370
+ - Check configuration files exist and are valid YAML
371
+
372
+ ### Entity Statements Not Validating
373
+
374
+ - Verify keys are correctly configured
375
+ - Check entity IDs match between servers
376
+ - Ensure trust anchors are configured if using trust chains
377
+
378
+ ### Request Objects Rejected
379
+
380
+ - Verify RP's entity statement is accessible
381
+ - Check RP's JWKS contains the signing key
382
+ - Ensure request object is properly signed
383
+ - Verify encryption if required by OP
384
+
385
+ ### Trust Chain Resolution Fails
386
+
387
+ - Verify trust anchors are configured
388
+ - Check authority_hints are correct
389
+ - Ensure all entity statements in chain are valid
390
+ - Verify subordinate statements are available
391
+
392
+ ## Next Steps
393
+
394
+ 1. **Add More Error Scenarios**: Extend error injection modes
395
+ 2. **Performance Testing**: Add load testing scenarios
396
+ 3. **Security Testing**: Add fuzzing and penetration tests
397
+ 4. **Trust Mark Testing**: Add trust mark validation
398
+ 5. **Metadata Policy Testing**: Add comprehensive policy merging tests
399
+