1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
use crate::{types::*, KeycloakError}; use serde::{Deserialize, Serialize}; use serde_json::json; use std::borrow::Cow; mod rest; pub struct KeycloakAdmin<'a> { url: String, client: reqwest::Client, admin_token: KeycloakAdminToken<'a>, } #[derive(Debug, Deserialize, Serialize)] pub struct KeycloakAdminToken<'a> { access_token: Cow<'a, str>, expires_in: usize, #[serde(rename = "not-before-policy")] not_before_policy: Option<usize>, refresh_expires_in: Option<usize>, refresh_token: Option<Cow<'a, str>>, scope: Cow<'a, str>, session_state: Option<Cow<'a, str>>, token_type: Cow<'a, str>, } impl<'a> KeycloakAdminToken<'a> { pub async fn get(&self, _url: &str) -> Result<Cow<'_, str>, KeycloakError> { Ok(self.access_token.clone()) } pub async fn acquire( url: &str, username: &str, password: &str, client: &reqwest::Client, ) -> Result<KeycloakAdminToken<'a>, KeycloakError> { let response = client .post(&format!( "{}/auth/realms/master/protocol/openid-connect/token", url )) .form(&json!({ "username": username, "password": password, "client_id": "admin-cli", "grant_type": "password" })) .send() .await?; Ok(error_check(response).await?.json().await?) } } async fn error_check(response: reqwest::Response) -> Result<reqwest::Response, KeycloakError> { if !response.status().is_success() { let status = response.status().into(); let text = response.text().await?; return Err(KeycloakError::HttpFailure { status, body: serde_json::from_str(&text).ok(), text, }); } Ok(response) } impl<'a> KeycloakAdmin<'a> { pub fn new(url: &str, admin_token: KeycloakAdminToken<'a>, client: reqwest::Client) -> Self { Self { url: url.into(), client, admin_token, } } }