Add complete system qualification evidence
This commit is contained in:
parent
775dd61963
commit
6952767503
1 changed files with 1256 additions and 84 deletions
|
|
@ -47,6 +47,14 @@ pub async fn revoke_remora_grants() -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn restore_remora_grants() -> Result<(), String> {
|
||||
match required_env("REMORA_OIDC_PROVIDER").as_str() {
|
||||
"keycloak" => restore_keycloak_remora_roles().await,
|
||||
"zitadel" => restore_zitadel_remora_roles().await,
|
||||
provider => Err(format!("unsupported OIDC provider {provider}")),
|
||||
}
|
||||
}
|
||||
|
||||
async fn mint_keycloak_token() -> Result<String, String> {
|
||||
let response = Client::new()
|
||||
.post(format!(
|
||||
|
|
@ -262,6 +270,103 @@ async fn revoke_keycloak_remora_roles() -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn restore_keycloak_remora_roles() -> Result<(), String> {
|
||||
let realm = required_env("REMORA_OIDC_TENANT");
|
||||
let client_id = required_env("REMORA_OIDC_CLIENT_ID");
|
||||
let username = required_env("REMORA_OIDC_USERNAME");
|
||||
let client = Client::new();
|
||||
let admin_response = client
|
||||
.post("http://keycloak.remora.test:8080/realms/master/protocol/openid-connect/token")
|
||||
.form(&[
|
||||
("grant_type", "password"),
|
||||
("client_id", "admin-cli"),
|
||||
("username", "remora-admin"),
|
||||
("password", "synthetic-keycloak"),
|
||||
])
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let admin_body: Value = admin_response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let admin_token = admin_body["access_token"]
|
||||
.as_str()
|
||||
.ok_or_else(|| "keycloak admin token missing".to_owned())?;
|
||||
let users: Value = client
|
||||
.get(format!(
|
||||
"http://keycloak.remora.test:8080/admin/realms/{realm}/users?username={username}&exact=true"
|
||||
))
|
||||
.bearer_auth(admin_token)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let user_id = users
|
||||
.as_array()
|
||||
.and_then(|rows| rows.first())
|
||||
.and_then(|row| row["id"].as_str())
|
||||
.ok_or_else(|| "keycloak user missing".to_owned())?;
|
||||
let clients: Value = client
|
||||
.get(format!(
|
||||
"http://keycloak.remora.test:8080/admin/realms/{realm}/clients?clientId={client_id}"
|
||||
))
|
||||
.bearer_auth(admin_token)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let client_uuid = clients
|
||||
.as_array()
|
||||
.and_then(|rows| rows.first())
|
||||
.and_then(|row| row["id"].as_str())
|
||||
.ok_or_else(|| "keycloak client missing".to_owned())?;
|
||||
let roles: Value = client
|
||||
.get(format!(
|
||||
"http://keycloak.remora.test:8080/admin/realms/{realm}/clients/{client_uuid}/roles"
|
||||
))
|
||||
.bearer_auth(admin_token)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let storage_role = required_env("REMORA_OIDC_STORAGE_ROLE");
|
||||
let roles = roles
|
||||
.as_array()
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter(|role| {
|
||||
role["name"]
|
||||
.as_str()
|
||||
.is_some_and(|name| name == "remora:v1:admin" || name == storage_role)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let response = client
|
||||
.post(format!(
|
||||
"http://keycloak.remora.test:8080/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_uuid}"
|
||||
))
|
||||
.bearer_auth(admin_token)
|
||||
.json(&roles)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
if response.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
"keycloak role restore failed: {}",
|
||||
response.status()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn revoke_zitadel_remora_roles() -> Result<(), String> {
|
||||
let issuer = required_env("REMORA_OIDC_ISSUER");
|
||||
let organization = required_env("REMORA_OIDC_TENANT");
|
||||
|
|
@ -316,3 +421,64 @@ async fn revoke_zitadel_remora_roles() -> Result<(), String> {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn restore_zitadel_remora_roles() -> Result<(), String> {
|
||||
let issuer = required_env("REMORA_OIDC_ISSUER");
|
||||
let organization = required_env("REMORA_OIDC_TENANT");
|
||||
let user_id = required_env("REMORA_OIDC_USER_ID");
|
||||
let project_id = required_env("REMORA_OIDC_PROJECT_ID");
|
||||
let token = required_env("REMORA_OIDC_MGMT_TOKEN");
|
||||
let host = issuer
|
||||
.strip_prefix("http://")
|
||||
.or_else(|| issuer.strip_prefix("https://"))
|
||||
.unwrap_or(&issuer);
|
||||
let client = Client::new();
|
||||
let grants: Value = client
|
||||
.post(format!("{issuer}/management/v1/users/grants/_search"))
|
||||
.header("Host", host)
|
||||
.bearer_auth(&token)
|
||||
.header("x-zitadel-orgid", &organization)
|
||||
.json(&json!({ "queries": [{ "userIdQuery": { "userId": user_id } }] }))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
let grant_id = grants["result"]
|
||||
.as_array()
|
||||
.and_then(|rows| {
|
||||
rows.iter().find(|row| {
|
||||
row["projectId"]
|
||||
.as_str()
|
||||
.is_some_and(|value| value == project_id)
|
||||
})
|
||||
})
|
||||
.and_then(|row| row["id"].as_str())
|
||||
.ok_or_else(|| "zitadel project grant missing".to_owned())?;
|
||||
let response = client
|
||||
.put(format!(
|
||||
"{issuer}/management/v1/users/{user_id}/grants/{grant_id}"
|
||||
))
|
||||
.header("Host", host)
|
||||
.bearer_auth(token)
|
||||
.header("x-zitadel-orgid", organization)
|
||||
.json(&json!({
|
||||
"roleKeys": [
|
||||
"test-user",
|
||||
"remora:v1:admin",
|
||||
required_env("REMORA_OIDC_STORAGE_ROLE")
|
||||
]
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
if response.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
"zitadel role restore failed: {}",
|
||||
response.status()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue