Add tests for some basic /token error conditions
Signed-off-by: Olivier 'reivilibre <olivier@librepush.net>
This commit is contained in:
parent
e908ef7324
commit
e6e6f38db3
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
source: src/tests/test_oidc_auth_flow.rs
|
||||||
|
expression: "(headers, json)"
|
||||||
|
---
|
||||||
|
- access-control-allow-origin: "*"
|
||||||
|
access-control-expose-headers: "*"
|
||||||
|
content-length: "75"
|
||||||
|
content-type: application/json
|
||||||
|
- error: invalid_request
|
||||||
|
error_description: "`code` parameter missing."
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
source: src/tests/test_oidc_auth_flow.rs
|
||||||
|
expression: "(headers, json)"
|
||||||
|
---
|
||||||
|
- access-control-allow-origin: "*"
|
||||||
|
access-control-expose-headers: "*"
|
||||||
|
content-length: "77"
|
||||||
|
content-type: application/json
|
||||||
|
- error: invalid_request
|
||||||
|
error_description: "`code` parameter malformed."
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
source: src/tests/test_oidc_auth_flow.rs
|
||||||
|
expression: "(headers, json)"
|
||||||
|
---
|
||||||
|
- access-control-allow-origin: "*"
|
||||||
|
access-control-expose-headers: "*"
|
||||||
|
content-length: "84"
|
||||||
|
content-type: application/json
|
||||||
|
- error: invalid_request
|
||||||
|
error_description: "`code_verifier` parameter missing."
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
source: src/tests/test_oidc_auth_flow.rs
|
||||||
|
expression: "(headers, json)"
|
||||||
|
---
|
||||||
|
- access-control-allow-origin: "*"
|
||||||
|
access-control-expose-headers: "*"
|
||||||
|
content-length: "74"
|
||||||
|
content-type: application/json
|
||||||
|
- error: invalid_grant
|
||||||
|
error_description: Code challenge is invalid.
|
@ -49,7 +49,7 @@ async fn test_full_flow() {
|
|||||||
let pwhash = create_password_hash("secret", &sys.config.password_hashing).unwrap();
|
let pwhash = create_password_hash("secret", &sys.config.password_hashing).unwrap();
|
||||||
let _: () = sys
|
let _: () = sys
|
||||||
.store
|
.store
|
||||||
.txn(|mut txn| {
|
.txn(|txn| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
"INSERT INTO users (user_name, user_id, created_at_utc, password_hash, locked) VALUES ($1, $2, NOW(), $3, $4) RETURNING user_id",
|
"INSERT INTO users (user_name, user_id, created_at_utc, password_hash, locked) VALUES ($1, $2, NOW(), $3, $4) RETURNING user_id",
|
||||||
@ -219,3 +219,140 @@ async fn test_userinfo_bad_auth() {
|
|||||||
assert_eq!(status, 401);
|
assert_eq!(status, 401);
|
||||||
assert_yaml_snapshot!("3. wrong auth token", (headers, text));
|
assert_yaml_snapshot!("3. wrong auth token", (headers, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests TODO:
|
||||||
|
// /token conflict — including checking that the old access token gets revoked
|
||||||
|
|
||||||
|
/// Tests error conditions in the /token endpoint
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_token_errors() {
|
||||||
|
let sys = basic_system().await;
|
||||||
|
|
||||||
|
let uuid = Uuid::nil();
|
||||||
|
let pwhash = create_password_hash("secret", &sys.config.password_hashing).unwrap();
|
||||||
|
let _: () = sys
|
||||||
|
.store
|
||||||
|
.txn(|txn| {
|
||||||
|
Box::pin(async move {
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO users (user_name, user_id, created_at_utc, password_hash, locked) VALUES ($1, $2, NOW(), $3, $4) RETURNING user_id",
|
||||||
|
).bind("robert").bind(uuid).bind(pwhash).bind(false)
|
||||||
|
.fetch_one(&mut **txn.txn)
|
||||||
|
.await.unwrap();
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let client = TestClient::new(sys.web);
|
||||||
|
|
||||||
|
///// These requests are on behalf of the user's browser /////
|
||||||
|
|
||||||
|
const CODE_VERIFIER: &str = "verifying";
|
||||||
|
// base64(sha256("verifying"))
|
||||||
|
const CODE_CHALLENGE: &str = "LeU9Sprdh-i2mzasKGh8-hmbnmzk48l3Siw390dKY3M";
|
||||||
|
|
||||||
|
// 1. /login request with credentials
|
||||||
|
let resp = client
|
||||||
|
.post("/login")
|
||||||
|
.form(&btreemap! {
|
||||||
|
"username" => "robert",
|
||||||
|
"password" => "secret",
|
||||||
|
"xsrf" => "HL4qRFKUlBqkrPTvAQ6z-w",
|
||||||
|
})
|
||||||
|
.header("Cookie", "__Host-SessionlessXsrf=HL4qRFKUlBqkrPTvAQ6z-w")
|
||||||
|
// /login is rate-limited by IP source and needs an IP
|
||||||
|
.header("X-Forwarded-For", "0.0.0.0")
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, _headers, _text) =
|
||||||
|
dump_resp_text("1. /login request with credentials", resp).await;
|
||||||
|
assert_eq!(status, 302);
|
||||||
|
|
||||||
|
let auth_loc = format!("/oidc/auth?scope=openid&client_id=aclient&response_type=code&state=wombat&redirect_uri=http:%2F%2Faclient.example.com%2Fredirect&code_challenge={CODE_CHALLENGE}&code_challenge_method=S256&nonce=noncey");
|
||||||
|
|
||||||
|
// 2. /auth request with confirmation
|
||||||
|
let resp = client
|
||||||
|
.post(&auth_loc)
|
||||||
|
.header(
|
||||||
|
"Cookie",
|
||||||
|
"__Host-LoginSession=HL4qRFKUlBqkrPTvAQ6z-xpYf2uo9sbO68miVnnz7KE",
|
||||||
|
)
|
||||||
|
.form(&btreemap! {
|
||||||
|
"action" => "accept",
|
||||||
|
"xsrf" => "0.48qkqIorf3dyk1LgVQwyNT82yDHyqHbXge09Rvfsz8Y",
|
||||||
|
})
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, _headers, _text) = dump_resp_text("2. POST /auth after confirmation", resp).await;
|
||||||
|
assert_eq!(status, 302);
|
||||||
|
|
||||||
|
///// At this point, we make requests on behalf of the client /////
|
||||||
|
|
||||||
|
// 3. /token request with no code
|
||||||
|
let resp = client
|
||||||
|
.post("/oidc/token")
|
||||||
|
.header("Authorization", "Basic YWNsaWVudDpzZWNyZXRB")
|
||||||
|
.form(&btreemap! {
|
||||||
|
"code_verifier" => CODE_VERIFIER,
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"redirect_uri" => "http://aclient.example.com/redirect",
|
||||||
|
})
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, headers, text) = dump_resp_text("3. /token no code", resp).await;
|
||||||
|
assert_eq!(status, 400);
|
||||||
|
let json: BTreeMap<String, serde_json::Value> = serde_json::from_str(&text).unwrap();
|
||||||
|
assert_yaml_snapshot!("3/token_no_code", (headers, json));
|
||||||
|
|
||||||
|
// 4. /token request with malformed code (not long enough)
|
||||||
|
let resp = client
|
||||||
|
.post("/oidc/token")
|
||||||
|
.header("Authorization", "Basic YWNsaWVudDpzZWNyZXRB")
|
||||||
|
.form(&btreemap! {
|
||||||
|
"code" => "aaaa",
|
||||||
|
"code_verifier" => CODE_VERIFIER,
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"redirect_uri" => "http://aclient.example.com/redirect",
|
||||||
|
})
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, headers, text) = dump_resp_text("4. /token malformed code", resp).await;
|
||||||
|
assert_eq!(status, 400);
|
||||||
|
let json: BTreeMap<String, serde_json::Value> = serde_json::from_str(&text).unwrap();
|
||||||
|
assert_yaml_snapshot!("4/token_malformed_code", (headers, json));
|
||||||
|
|
||||||
|
// 5. /token request with no code_verifier
|
||||||
|
let resp = client
|
||||||
|
.post("/oidc/token")
|
||||||
|
.header("Authorization", "Basic YWNsaWVudDpzZWNyZXRB")
|
||||||
|
.form(&btreemap! {
|
||||||
|
"code" => "HL4qRFKUlBqkrPTvAQ6z-xpYf2uo9sbO",
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"redirect_uri" => "http://aclient.example.com/redirect",
|
||||||
|
})
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, headers, text) = dump_resp_text("5. /token no verifier", resp).await;
|
||||||
|
assert_eq!(status, 400);
|
||||||
|
let json: BTreeMap<String, serde_json::Value> = serde_json::from_str(&text).unwrap();
|
||||||
|
assert_yaml_snapshot!("5/token_no_verifier", (headers, json));
|
||||||
|
|
||||||
|
// 6. /token request with wrong code_verifier
|
||||||
|
let resp = client
|
||||||
|
.post("/oidc/token")
|
||||||
|
.header("Authorization", "Basic YWNsaWVudDpzZWNyZXRB")
|
||||||
|
.form(&btreemap! {
|
||||||
|
"code" => "HL4qRFKUlBqkrPTvAQ6z-xpYf2uo9sbO",
|
||||||
|
"code_verifier" => "i'm wrong",
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"redirect_uri" => "http://aclient.example.com/redirect",
|
||||||
|
})
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
let (status, headers, text) = dump_resp_text("6. /token wrong verifier", resp).await;
|
||||||
|
assert_eq!(status, 400);
|
||||||
|
let json: BTreeMap<String, serde_json::Value> = serde_json::from_str(&text).unwrap();
|
||||||
|
assert_yaml_snapshot!("6/token_wrong_verifier", (headers, json));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user