exchange.rs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //! Token-exchange rejection rows for `tests/e2e_edge_matrix.rs`.
  2. //!
  3. //! Both rows reach the real `/token` dispatcher: a missing `subject_token` is
  4. //! a grant-level `invalid_grant`, while a repeated known parameter is rejected
  5. //! by the pre-dispatch duplicate gate as `invalid_request`.
  6. use d_oauth::db::TokenEndpointAuthMethod;
  7. use reqwest::StatusCode;
  8. use serde_json::json;
  9. use super::{
  10. dpop::DpopKey,
  11. edge::ensure_error,
  12. harness::{SeedClientOpts, TestError, World, open_rate_limit, seed_client_bound},
  13. };
  14. /// Token-exchange grant URN (RFC 8693).
  15. const EXCHANGE_GRANT: &str = "urn:ietf:params:oauth:grant-type:token-exchange";
  16. /// Access-token type URN used for both token-type members.
  17. const ACCESS_TOKEN_TYPE: &str = "urn:ietf:params:oauth:token-type:access_token";
  18. /// Exchange caller holding the exchange grant (DPoP-bound).
  19. const CALLER_ID: &str = "e2e-edge-exchange-caller";
  20. /// Exchange caller secret.
  21. const CALLER_SECRET: &str = "e2e-edge-exchange-secret-1a2b3c4d5e6f708192a0";
  22. /// A missing `subject_token` is `invalid_grant` at the grant, not
  23. /// `invalid_request`.
  24. pub async fn missing_subject_token() -> Result<(), TestError> {
  25. let world = World::start_with(open_rate_limit(), json!({"allow_token_exchange": true})).await?;
  26. seed_client_bound(
  27. &world.pool,
  28. &world.state.keys,
  29. CALLER_ID,
  30. Some(CALLER_SECRET),
  31. &SeedClientOpts {
  32. grants: &[EXCHANGE_GRANT],
  33. scope: "read",
  34. method: TokenEndpointAuthMethod::ClientSecretBasic,
  35. dpop_bound: true,
  36. },
  37. )
  38. .await?;
  39. let proof =
  40. DpopKey::generate()?.proof("POST", &format!("{}/token", world.state.config.issuer))?;
  41. let (status, _, body) = world
  42. .post_form(
  43. "/token",
  44. &[
  45. ("grant_type", EXCHANGE_GRANT),
  46. ("subject_token_type", ACCESS_TOKEN_TYPE),
  47. ("requested_token_type", ACCESS_TOKEN_TYPE),
  48. ],
  49. Some((CALLER_ID, CALLER_SECRET)),
  50. &[("dpop", proof.as_str())],
  51. )
  52. .await?;
  53. ensure_error(status, &body, StatusCode::BAD_REQUEST, "invalid_grant")
  54. }
  55. /// A repeated `scope` or `grant_type` is rejected before dispatch as
  56. /// `invalid_request`.
  57. pub async fn duplicate_parameter() -> Result<(), TestError> {
  58. let world = World::start_with(open_rate_limit(), json!({"allow_token_exchange": true})).await?;
  59. let duplicate_scope = [
  60. ("grant_type", EXCHANGE_GRANT),
  61. ("subject_token", "subject"),
  62. ("subject_token_type", ACCESS_TOKEN_TYPE),
  63. ("scope", "read"),
  64. ("scope", "read"),
  65. ];
  66. let duplicate_grant_type = [
  67. ("grant_type", EXCHANGE_GRANT),
  68. ("grant_type", "refresh_token"),
  69. ("scope", "read"),
  70. ];
  71. for params in [&duplicate_scope[..], &duplicate_grant_type[..]] {
  72. let (status, _, body) = world.post_form("/token", params, None, &[]).await?;
  73. ensure_error(status, &body, StatusCode::BAD_REQUEST, "invalid_request")?;
  74. }
  75. Ok(())
  76. }