Skip to content

Commit

Permalink
Migrate security_keyvault to new azure_core::error scheme (#782)
Browse files Browse the repository at this point in the history
* Migrate security_keyvault to new azure_core::error scheme
Co-authored-by: John Batty <[email protected]>
  • Loading branch information
johnbatty authored Jun 7, 2022
1 parent fb93e37 commit 1fa5bec
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 130 deletions.
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

0 comments on commit 1fa5bec

Please sign in to comment.