summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyborus <cyborus@cyborus.xyz>2024-05-23 01:28:44 +0200
committerCyborus <cyborus@cyborus.xyz>2024-05-23 01:28:44 +0200
commit014a90048f5576d63ba14911065d04a45736cf92 (patch)
tree836d5bd32032394e077a37e34d845ac45c7c7e2a
parentadd oauth2 authentication (diff)
downloadforgejo-api-014a90048f5576d63ba14911065d04a45736cf92.tar.xz
forgejo-api-014a90048f5576d63ba14911065d04a45736cf92.zip
add oauth2 testing
-rw-r--r--Cargo.lock75
-rw-r--r--Cargo.toml1
-rw-r--r--tests/ci_test.rs103
3 files changed, 178 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a8f4e51..edfc2e7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -90,6 +90,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
+name = "cookie"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
+dependencies = [
+ "percent-encoding",
+ "time",
+ "version_check",
+]
+
+[[package]]
+name = "cookie_store"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa"
+dependencies = [
+ "cookie",
+ "idna 0.2.3",
+ "log",
+ "publicsuffix",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "time",
+ "url",
+]
+
+[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -358,6 +386,27 @@ dependencies = [
[[package]]
name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
@@ -428,6 +477,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
+name = "matches"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
+
+[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -586,6 +641,22 @@ dependencies = [
]
[[package]]
+name = "psl-types"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
+
+[[package]]
+name = "publicsuffix"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
+dependencies = [
+ "idna 0.3.0",
+ "psl-types",
+]
+
+[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -611,6 +682,8 @@ checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
dependencies = [
"base64",
"bytes",
+ "cookie",
+ "cookie_store",
"encoding_rs",
"futures-core",
"futures-util",
@@ -1005,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
"form_urlencoded",
- "idna",
+ "idna 0.5.0",
"percent-encoding",
"serde",
]
diff --git a/Cargo.toml b/Cargo.toml
index d38f474..94f5e81 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,4 +24,5 @@ zeroize = "1.7.0"
[dev-dependencies]
eyre = "0.6.9"
+reqwest = { version = "0.11.18", features = ["cookies"] }
tokio = { version = "1.29.1", features = ["net", "fs", "rt", "macros"] }
diff --git a/tests/ci_test.rs b/tests/ci_test.rs
index 6eca774..269c522 100644
--- a/tests/ci_test.rs
+++ b/tests/ci_test.rs
@@ -430,3 +430,106 @@ async fn admin() {
.await
.expect("failed to delete hook");
}
+
+#[tokio::test]
+async fn oauth2_login() {
+ let api = get_api();
+ let opt = forgejo_api::structs::CreateOAuth2ApplicationOptions {
+ confidential_client: Some(true),
+ name: Some("Test Application".into()),
+ redirect_uris: Some(vec!["http://127.0.0.1:48879/".into()]),
+ };
+ let app = api.user_create_oauth2_application(opt).await.unwrap();
+ let client_id = app.client_id.unwrap();
+ let client_secret = app.client_secret.unwrap();
+
+ let base_url = &std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap();
+
+ let client = reqwest::Client::builder()
+ .cookie_store(true)
+ .redirect(reqwest::redirect::Policy::none())
+ .build()
+ .unwrap();
+
+ // Log in via the web interface
+ let _ = client
+ .post(&format!("{base_url}user/login"))
+ .form(&[("user_name", "TestingAdmin"), ("password", "password")])
+ .send()
+ .await
+ .unwrap()
+ .error_for_status()
+ .unwrap();
+
+ // Load the authorization page
+ let response = client
+ .get(&format!(
+ "{base_url}login/oauth/authorize\
+ ?client_id={client_id}\
+ &redirect_uri=http%3A%2F%2F127.0.0.1%3A48879%2F\
+ &response_type=code\
+ &state=theyve"
+ ))
+ .send()
+ .await
+ .unwrap()
+ .error_for_status()
+ .unwrap();
+ let csrf = response.cookies().find(|x| x.name() == "_csrf").unwrap();
+
+ // Authorize the new application via the web interface
+ let response = client
+ .post(&format!("{base_url}login/oauth/grant"))
+ .form(&[
+ ("_csrf", csrf.value()),
+ ("client_id", &client_id),
+ ("state", "theyve"),
+ ("scope", ""),
+ ("nonce", ""),
+ ("redirect_uri", "http://127.0.0.1:48879/"),
+ ])
+ .send()
+ .await
+ .unwrap()
+ .error_for_status()
+ .unwrap();
+
+ // Extract the code from the redirect url
+ let location = response.headers().get(reqwest::header::LOCATION).unwrap();
+ let location = url::Url::parse(dbg!(location.to_str().unwrap())).unwrap();
+ let mut code = None;
+ for (key, value) in location.query_pairs() {
+ if key == "code" {
+ code = Some(value.into_owned());
+ } else if key == "error_description" {
+ panic!("{value}");
+ }
+ }
+ let code = code.unwrap();
+
+ // Redeem the code and check it works
+ let url = url::Url::parse(&base_url).unwrap();
+ let api = Forgejo::new(forgejo_api::Auth::None, url.clone()).unwrap();
+
+ let request = forgejo_api::structs::OAuthTokenRequest::Confidential {
+ client_id: &client_id,
+ client_secret: &client_secret,
+ code: &code,
+ redirect_uri: url::Url::parse("http://127.0.0.1:48879/").unwrap(),
+ };
+ let token = api.oauth_get_access_token(request).await.unwrap();
+ let token_api =
+ Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url.clone()).unwrap();
+ let myself = token_api.user_get_current().await.unwrap();
+ assert_eq!(myself.login.as_deref(), Some("TestingAdmin"));
+
+ let request = forgejo_api::structs::OAuthTokenRequest::Refresh {
+ refresh_token: &token.refresh_token,
+ client_id: &client_id,
+ client_secret: &client_secret,
+ };
+ let token = token_api.oauth_get_access_token(request).await.unwrap();
+ let token_api = Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url).unwrap();
+ let myself = token_api.user_get_current().await.unwrap();
+ assert_eq!(myself.login.as_deref(), Some("TestingAdmin"));
+}