1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Write tests for the token revocation endpoint

This commit is contained in:
Quentin Gliech
2023-02-20 15:52:01 +01:00
parent 543b4b229f
commit a6cd4412c1
4 changed files with 187 additions and 2 deletions

View File

@ -76,8 +76,11 @@ oauth2-types = { path = "../oauth2-types" }
[dev-dependencies]
indoc = "2.0.0"
insta = "1.26.0"
tracing-subscriber = "0.3.16"
[features]
default = ["webpki-roots"]
# Use the native root certificates
native-roots = ["mas-axum-utils/native-roots", "mas-http/native-roots"]
# Use the webpki root certificates

View File

@ -367,6 +367,7 @@ where
#[cfg(test)]
async fn test_state(pool: sqlx::PgPool) -> Result<AppState, anyhow::Error> {
use mas_email::MailTransport;
use mas_keystore::{JsonWebKey, JsonWebKeySet, PrivateKey};
use crate::passwords::Hasher;
@ -378,8 +379,13 @@ async fn test_state(pool: sqlx::PgPool) -> Result<AppState, anyhow::Error> {
let templates = Templates::load(workspace_root.join("templates"), url_builder.clone()).await?;
// TODO: add test keys to the store
let key_store = Keystore::default();
// TODO: add more test keys to the store
let rsa =
PrivateKey::load_pem(include_str!("../../keystore/tests/keys/rsa.pkcs1.pem")).unwrap();
let rsa = JsonWebKey::new(rsa).with_kid("test-rsa");
let jwks = JsonWebKeySet::new(vec![rsa]);
let key_store = Keystore::new(jwks);
let encrypter = Encrypter::new(&[0x42; 32]);

View File

@ -198,3 +198,178 @@ pub(crate) async fn post(
Ok(())
}
#[cfg(test)]
mod tests {
use hyper::{
header::{AUTHORIZATION, CONTENT_TYPE},
Request,
};
use mas_data_model::AuthorizationCode;
use mas_router::SimpleRoute;
use mas_storage::{RepositoryAccess, RepositoryTransaction, SystemClock};
use mas_storage_pg::PgRepository;
use oauth2_types::{
registration::ClientRegistrationResponse,
requests::{AccessTokenResponse, ResponseMode},
scope::{Scope, OPENID},
};
use rand::SeedableRng;
use sqlx::PgPool;
use tower::{Service, ServiceExt};
use super::*;
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
async fn test_revoke_access_token(pool: PgPool) {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_test_writer()
.init();
let clock = SystemClock::default();
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(42);
let state = crate::test_state(pool.clone()).await.unwrap();
let mut app = crate::api_router().with_state(state);
let request = Request::post(mas_router::OAuth2RegistrationEndpoint::PATH)
.header(CONTENT_TYPE, "application/json")
.body(
serde_json::json!({
"client_uri": "https://example.com/",
"redirect_uris": ["https://example.com/callback"],
"contacts": ["contact@example.com"],
"token_endpoint_auth_method": "client_secret_post",
"response_types": ["code"],
"grant_types": ["authorization_code"],
})
.to_string(),
)
.unwrap();
let response = app.ready().await.unwrap().call(request).await.unwrap();
assert_eq!(response.status(), StatusCode::CREATED);
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
let client_registration: ClientRegistrationResponse =
serde_json::from_slice(&body).unwrap();
let client_id = client_registration.client_id;
let client_secret = client_registration.client_secret.unwrap();
// Let's provision a user and create a session for them. This part is hard to
// test with just HTTP requests, so we'll use the repository directly.
let mut repo = PgRepository::from_pool(&pool).await.unwrap();
let user = repo
.user()
.add(&mut rng, &clock, "alice".to_owned())
.await
.unwrap();
let browser_session = repo
.browser_session()
.add(&mut rng, &clock, &user)
.await
.unwrap();
// Lookup the client in the database.
let client = repo
.oauth2_client()
.find_by_client_id(&client_id)
.await
.unwrap()
.unwrap();
// Start a grant
let grant = repo
.oauth2_authorization_grant()
.add(
&mut rng,
&clock,
&client,
"https://example.com/redirect".parse().unwrap(),
Scope::from_iter([OPENID]),
Some(AuthorizationCode {
code: "thisisaverysecurecode".to_owned(),
pkce: None,
}),
Some("state".to_owned()),
Some("nonce".to_owned()),
None,
ResponseMode::Query,
true,
false,
)
.await
.unwrap();
let session = repo
.oauth2_session()
.create_from_grant(&mut rng, &clock, &grant, &browser_session)
.await
.unwrap();
let grant = repo
.oauth2_authorization_grant()
.fulfill(&clock, &session, grant)
.await
.unwrap();
Box::new(repo).save().await.unwrap();
// Now call the token endpoint to get an access token.
let request = Request::post(mas_router::OAuth2TokenEndpoint::PATH)
.header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.body(
format!(
"grant_type=authorization_code&code={code}&redirect_uri={redirect_uri}&client_id={client_id}&client_secret={client_secret}",
code = grant.code.unwrap().code,
redirect_uri = grant.redirect_uri,
),
)
.unwrap();
let response = app.ready().await.unwrap().call(request).await.unwrap();
let status = response.status();
assert_eq!(status, StatusCode::OK);
let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
let token: AccessTokenResponse = serde_json::from_slice(&body).unwrap();
// Let's call the userinfo endpoint to make sure we can access it.
let request = Request::get(mas_router::OidcUserinfo::PATH)
.header(AUTHORIZATION, format!("Bearer {}", token.access_token))
.body(String::new())
.unwrap();
let response = app.ready().await.unwrap().call(request).await.unwrap();
let status = response.status();
assert_eq!(status, StatusCode::OK);
// Now let's revoke the access token.
let request = Request::post(mas_router::OAuth2Revocation::PATH)
.header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.body(format!(
"token={token}&token_type_hint=access_token&client_id={client_id}&client_secret={client_secret}",
token = token.access_token
))
.unwrap();
let response = app.ready().await.unwrap().call(request).await.unwrap();
let status = response.status();
assert_eq!(status, StatusCode::OK);
// Call the userinfo endpoint again to make sure we can't access it anymore.
let request = Request::get(mas_router::OidcUserinfo::PATH)
.header(AUTHORIZATION, format!("Bearer {}", token.access_token))
.body(String::new())
.unwrap();
let response = app.ready().await.unwrap().call(request).await.unwrap();
let status = response.status();
assert_eq!(status, StatusCode::UNAUTHORIZED);
// TODO: test refreshing the access token, test refresh token revocation
}
}