Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate security_keyvault to new azure_core::error scheme #782

Merged
merged 6 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion sdk/security_keyvault/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ edition = "2021"

[dependencies]
base64 = "0.13"
thiserror = "1.0"
reqwest = { version = "0.11", features = ["json"] }
chrono = { version = "0.4", features = ["serde"] }
const_format = "0.2.13"
Expand Down
26 changes: 12 additions & 14 deletions sdk/security_keyvault/src/certificate.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::client::API_VERSION_PARAM;
use crate::CertificateClient;
use crate::Error;
use azure_core::error::{Error, ErrorKind, ResultExt};

use azure_core::auth::TokenCredential;
use chrono::serde::{ts_seconds, ts_seconds_option};
Expand Down Expand Up @@ -205,10 +205,8 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {

let response_body = self.get_authed(uri.to_string()).await?;
let response = serde_json::from_str::<KeyVaultGetCertificateResponse>(&response_body)
.map_err(|error| Error::BackupCertificateParseError {
error,
certificate_name: name.to_string(),
response_body,
.with_context(ErrorKind::DataConversion, || {
format!("failed to parse get certificate response. uri: {uri} certificate_name: {name} response_body: {response_body}")
})?;
Ok(KeyVaultCertificate {
key_id: response.kid,
Expand Down Expand Up @@ -468,17 +466,17 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
uri.set_query(Some(API_VERSION_PARAM));

let response_body = self.post_authed(uri.to_string(), None).await?;
let backup_blob = serde_json::from_str::<KeyVaultCertificateBackupResponseRaw>(
&response_body,
)
.map_err(|error| Error::BackupCertificateParseError {
error,
certificate_name: name.to_string(),
response_body,
})?;
let backup_blob =
serde_json::from_str::<KeyVaultCertificateBackupResponseRaw>(&response_body)
.with_context(ErrorKind::DataConversion, || {
format!("failed to parse certificate backup response. uri: {uri}")
})?;

Ok(CertificateBackupResult {
backup: base64::decode(backup_blob.value)?,
backup: base64::decode(backup_blob.value).context(
ErrorKind::DataConversion,
"failed base64 decode of backup blob",
)?,
})
}

Expand Down
150 changes: 105 additions & 45 deletions sdk/security_keyvault/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Error;
use azure_core::auth::{TokenCredential, TokenResponse};
use azure_core::error::{Error, ErrorKind, ResultExt};
use const_format::formatcp;
use url::Url;

Expand Down Expand Up @@ -36,7 +36,9 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
/// let client = KeyClient::new("test-key-vault.vault.azure.net", &creds).unwrap();
/// ```
pub fn new(vault_url: &str, token_credential: &'a T) -> Result<Self, Error> {
let vault_url = Url::parse(vault_url)?;
let vault_url = Url::parse(vault_url).with_context(ErrorKind::DataConversion, || {
format!("failed to parse vault url: {vault_url}")
})?;
let endpoint = extract_endpoint(&vault_url)?;
let client = KeyClient {
vault_url,
Expand All @@ -57,7 +59,7 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
.token_credential
.get_token(&self.endpoint)
.await
.map_err(|_| Error::Authorization)?;
.context(ErrorKind::Credential, "get token failed")?;
self.token = Some(token);
Ok(())
}
Expand All @@ -71,7 +73,9 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await.unwrap();
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}

Expand All @@ -86,7 +90,9 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await?;
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}

Expand All @@ -107,15 +113,24 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
req = req.header("Content-Length", 0);
}

let resp = req.send().await?;

let body = resp.text().await?;

let body_serialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_serialized.get("error") {
let msg = err.get("message").ok_or(Error::UnparsableError)?;
Err(Error::General(msg.to_string()))
let resp = req.send().await.with_context(ErrorKind::Io, || {
format!("failed to send request. uri: {uri}")
})?;

let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
let body_deserialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_deserialized.get("error") {
let msg = err.get("message").ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!("failed to read message field from error response. body: {body}")
})
})?;
Err(Error::with_message(ErrorKind::Other, || {
format!("post response error: {msg}")
}))
} else {
Ok(body)
}
Expand All @@ -137,13 +152,20 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
.await
.unwrap();

let body = resp.text().await.unwrap();

let body_serialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_serialized.get("error") {
let msg = err.get("message").ok_or(Error::UnparsableError)?;
Err(Error::General(msg.to_string()))
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
let body_deserialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_deserialized.get("error") {
let msg = err.get("message").ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!("failed to read message field from error response. body: {body}")
})
})?;
Err(Error::with_message(ErrorKind::Other, || {
format!("patch response error: {}", msg)
}))
} else {
Ok(body)
}
Expand All @@ -159,7 +181,9 @@ impl<'a, T: TokenCredential> KeyClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await.unwrap();
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}
}
Expand Down Expand Up @@ -194,7 +218,9 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
/// let client = CertificateClient::new("test-key-vault.vault.azure.net", &creds).unwrap();
/// ```
pub fn new(vault_url: &str, token_credential: &'a T) -> Result<Self, Error> {
let vault_url = Url::parse(vault_url)?;
let vault_url = Url::parse(vault_url).with_context(ErrorKind::DataConversion, || {
format!("failed to parse vault url: {vault_url}")
})?;
let endpoint = extract_endpoint(&vault_url)?;
let client = CertificateClient {
vault_url,
Expand All @@ -215,7 +241,7 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
.token_credential
.get_token(&self.endpoint)
.await
.map_err(|_| Error::Authorization)?;
.context(ErrorKind::Credential, "failed to refresh token")?;
self.token = Some(token);
Ok(())
}
Expand All @@ -229,7 +255,9 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await.unwrap();
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}

Expand All @@ -244,7 +272,9 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await?;
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}

Expand All @@ -265,15 +295,26 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
req = req.header("Content-Length", 0);
}

let resp = req.send().await?;

let body = resp.text().await?;

let body_serialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_serialized.get("error") {
let msg = err.get("message").ok_or(Error::UnparsableError)?;
Err(Error::General(msg.to_string()))
let resp = req.send().await.with_context(ErrorKind::Io, || {
format!("failed to send request. uri: {uri}")
})?;

let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
let body_deserialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_deserialized.get("error") {
let msg = err.get("message").ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!(
"failed to read message field from error response. uri: {uri} body: {body}"
)
})
})?;
Err(Error::with_message(ErrorKind::Other, || {
format!("post response error: {msg}")
}))
} else {
Ok(body)
}
Expand All @@ -295,13 +336,22 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
.await
.unwrap();

let body = resp.text().await.unwrap();

let body_serialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_serialized.get("error") {
let msg = err.get("message").ok_or(Error::UnparsableError)?;
Err(Error::General(msg.to_string()))
let body = resp
.text()
.await
.context(ErrorKind::Io, "failed to read response body")?;

let body_deserialized = serde_json::from_str::<serde_json::Value>(&body).unwrap();

if let Some(err) = body_deserialized.get("error") {
let msg = err.get("message").ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!("failed to read message field from error response. body: {body}")
})
})?;
Err(Error::with_message(ErrorKind::Other, || {
format!("post response error. uri: {uri} msg: {msg}")
}))
} else {
Ok(body)
}
Expand All @@ -317,7 +367,9 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
.send()
.await
.unwrap();
let body = resp.text().await.unwrap();
let body = resp.text().await.with_context(ErrorKind::Io, || {
format!("failed to read response body text. uri: {uri}")
})?;
Ok(body)
}
}
Expand All @@ -327,10 +379,18 @@ impl<'a, T: TokenCredential> CertificateClient<'a, T> {
fn extract_endpoint(url: &Url) -> Result<String, Error> {
let endpoint = url
.host_str()
.ok_or(Error::DomainParse)?
.ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!("failed to parse host from url. url: {url}")
})
})?
.splitn(2, '.') // FIXME: replace with split_once() when it is in stable
.last()
.ok_or(Error::DomainParse)?;
.ok_or_else(|| {
Error::with_message(ErrorKind::DataConversion, || {
format!("failed to extract endpoint from url. url: {url}")
})
})?;
Ok(format!("{}://{}", url.scheme(), endpoint))
}

Expand Down
14 changes: 10 additions & 4 deletions sdk/security_keyvault/src/key.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::{Debug, Display};

use azure_core::auth::TokenCredential;
use azure_core::error::{Error, ErrorKind};
use base64::{CharacterSet, Config};
use chrono::serde::ts_seconds_option;
use chrono::{DateTime, Utc};
Expand All @@ -9,7 +10,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{Map, Value};

use crate::client::API_VERSION_PARAM;
use crate::Error;
use crate::KeyClient;

/// A KeyBundle consisting of a WebKey plus its attributes.
Expand Down Expand Up @@ -313,7 +313,9 @@ impl RsaDecryptParameters {
EncryptionAlgorithm::Rsa15
| EncryptionAlgorithm::RsaOaep
| EncryptionAlgorithm::RsaOaep256 => Ok(Self { algorithm }),
_ => Err(Error::EncryptionAlgorithmMismatch),
_ => Err(Error::with_message(ErrorKind::Other, || {
format!("unexpected encryption algorithm: {algorithm}")
})),
}
}
}
Expand Down Expand Up @@ -348,7 +350,9 @@ impl AesGcmDecryptParameters {
authentication_tag,
additional_authenticated_data,
}),
_ => Err(Error::EncryptionAlgorithmMismatch),
_ => Err(Error::with_message(ErrorKind::Other, || {
format!("unexpected encryption algorithm: {algorithm}")
})),
}
}
}
Expand All @@ -369,7 +373,9 @@ impl AesCbcDecryptParameters {
| EncryptionAlgorithm::A128CbcPad
| EncryptionAlgorithm::A192CbcPad
| EncryptionAlgorithm::A256CbcPad => Ok(Self { algorithm, iv }),
_ => Err(Error::EncryptionAlgorithmMismatch),
_ => Err(Error::with_message(ErrorKind::Other, || {
format!("unexpected encryption algorithm: {algorithm}")
})),
}
}
}
Expand Down
Loading