Skip to content

Commit

Permalink
Move login methods to auth (#319)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hinton authored Nov 3, 2023
1 parent 13a195c commit 5d9e997
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 165 deletions.
8 changes: 5 additions & 3 deletions crates/bitwarden-json/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ impl Client {

match cmd {
#[cfg(feature = "internal")]
Command::PasswordLogin(req) => self.0.password_login(&req).await.into_string(),
Command::PasswordLogin(req) => self.0.auth().login_password(&req).await.into_string(),
#[cfg(feature = "secrets")]
Command::AccessTokenLogin(req) => self.0.access_token_login(&req).await.into_string(),
Command::AccessTokenLogin(req) => {
self.0.auth().login_access_token(&req).await.into_string()
}
#[cfg(feature = "internal")]
Command::GetUserApiKey(req) => self.0.get_user_api_key(&req).await.into_string(),
#[cfg(feature = "internal")]
Command::ApiKeyLogin(req) => self.0.api_key_login(&req).await.into_string(),
Command::ApiKeyLogin(req) => self.0.auth().login_api_key(&req).await.into_string(),
#[cfg(feature = "internal")]
Command::Sync(req) => self.0.sync(&req).await.into_string(),
#[cfg(feature = "internal")]
Expand Down
5 changes: 5 additions & 0 deletions crates/bitwarden/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Deprecated

- `client.access_token_login()` is now deprecated and will be removed in a future release. Please
use `client.auth().login_access_token()` instead. (#319)

## [0.3.1] - 2023-10-13

### Changed
Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async fn test() -> Result<()> {

// Before we operate, we need to authenticate with a token
let token = AccessTokenLoginRequest { access_token: String::from("") };
client.access_token_login(&token).await.unwrap();
client.auth().login_access_token(&token).await.unwrap();

let org_id = SecretIdentifiersRequest { organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap() };
println!("Stored secrets: {:#?}", client.secrets().list(&org_id).await.unwrap());
Expand Down
159 changes: 153 additions & 6 deletions crates/bitwarden/src/auth/client_auth.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
use super::{
password::{password_strength, satisfies_policy, MasterPasswordPolicyOptions},
register::{make_register_keys, register},
RegisterKeyResponse, RegisterRequest,
#[cfg(feature = "secrets")]
use crate::auth::login::{login_access_token, AccessTokenLoginRequest, AccessTokenLoginResponse};
use crate::{auth::renew::renew_token, error::Result, Client};
#[cfg(feature = "internal")]
use crate::{
auth::{
login::{
login_api_key, login_password, send_two_factor_email, ApiKeyLoginRequest,
ApiKeyLoginResponse, PasswordLoginRequest, PasswordLoginResponse,
TwoFactorEmailRequest,
},
password::{password_strength, satisfies_policy, MasterPasswordPolicyOptions},
register::{make_register_keys, register},
RegisterKeyResponse, RegisterRequest,
},
client::kdf::Kdf,
};
use crate::{client::kdf::Kdf, error::Result, Client};

pub struct ClientAuth<'a> {
pub(crate) client: &'a mut crate::Client,
}

impl<'a> ClientAuth<'a> {
pub async fn renew_token(&mut self) -> Result<()> {
renew_token(self.client).await
}

#[cfg(feature = "secrets")]
pub async fn login_access_token(
&mut self,
input: &AccessTokenLoginRequest,
) -> Result<AccessTokenLoginResponse> {
login_access_token(self.client, input).await
}
}

#[cfg(feature = "internal")]
impl<'a> ClientAuth<'a> {
pub async fn password_strength(
&self,
Expand Down Expand Up @@ -37,14 +63,135 @@ impl<'a> ClientAuth<'a> {
make_register_keys(email, password, kdf)
}

#[cfg(feature = "internal")]
pub async fn register(&mut self, input: &RegisterRequest) -> Result<()> {
register(self.client, input).await
}

pub async fn prelogin(&mut self, email: String) -> Result<Kdf> {
use crate::auth::login::request_prelogin;

request_prelogin(self.client, email).await?.try_into()
}

pub async fn login_password(
&mut self,
input: &PasswordLoginRequest,
) -> Result<PasswordLoginResponse> {
login_password(self.client, input).await
}

pub async fn login_api_key(
&mut self,
input: &ApiKeyLoginRequest,
) -> Result<ApiKeyLoginResponse> {
login_api_key(self.client, input).await
}

pub async fn send_two_factor_email(&mut self, tf: &TwoFactorEmailRequest) -> Result<()> {
send_two_factor_email(self.client, tf).await
}
}

impl<'a> Client {
pub fn auth(&'a mut self) -> ClientAuth<'a> {
ClientAuth { client: self }
}
}

#[cfg(test)]
mod tests {

#[cfg(feature = "secrets")]
#[tokio::test]
async fn test_access_token_login() {
use wiremock::{matchers, Mock, ResponseTemplate};

use crate::{auth::login::AccessTokenLoginRequest, secrets_manager::secrets::*};

// Create the mock server with the necessary routes for this test
let (_server, mut client) = crate::util::start_mock(vec![
Mock::given(matchers::path("/identity/connect/token"))
.respond_with(ResponseTemplate::new(200).set_body_json(
serde_json::json!({
"access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMwMURENkE1MEU4NEUxRDA5MUM4MUQzQjAwQkY5MDEwQzg1REJEOUFSUzI1NiIsInR5cCI6\
ImF0K2p3dCIsIng1dCI6Ik1CM1dwUTZFNGRDUnlCMDdBTC1RRU1oZHZabyJ9.eyJuYmYiOjE2NzUxMDM3ODEsImV4cCI6MTY3NTEwNzM4MSwiaXNzIjo\
iaHR0cDovL2xvY2FsaG9zdCIsImNsaWVudF9pZCI6ImVjMmMxZDQ2LTZhNGItNDc1MS1hMzEwLWFmOTYwMTMxN2YyZCIsInN1YiI6ImQzNDgwNGNhLTR\
mNmMtNDM5Mi04NmI3LWFmOTYwMTMxNzVkMCIsIm9yZ2FuaXphdGlvbiI6ImY0ZTQ0YTdmLTExOTAtNDMyYS05ZDRhLWFmOTYwMTMxMjdjYiIsImp0aSI\
6IjU3QUU0NzQ0MzIwNzk1RThGQkQ4MUIxNDA2RDQyNTQyIiwiaWF0IjoxNjc1MTAzNzgxLCJzY29wZSI6WyJhcGkuc2VjcmV0cyJdfQ.GRKYzqgJZHEE\
ZHsJkhVZH8zjYhY3hUvM4rhdV3FU10WlCteZdKHrPIadCUh-Oz9DxIAA2HfALLhj1chL4JgwPmZgPcVS2G8gk8XeBmZXowpVWJ11TXS1gYrM9syXbv9j\
0JUCdpeshH7e56WnlpVynyUwIum9hmYGZ_XJUfmGtlKLuNjYnawTwLEeR005uEjxq3qI1kti-WFnw8ciL4a6HLNulgiFw1dAvs4c7J0souShMfrnFO3g\
SOHff5kKD3hBB9ynDBnJQSFYJ7dFWHIjhqs0Vj-9h0yXXCcHvu7dVGpaiNjNPxbh6YeXnY6UWcmHLDtFYsG2BWcNvVD4-VgGxXt3cMhrn7l3fSYuo32Z\
Yk4Wop73XuxqF2fmfmBdZqGI1BafhENCcZw_bpPSfK2uHipfztrgYnrzwvzedz0rjFKbhDyrjzuRauX5dqVJ4ntPeT9g_I5n71gLxiP7eClyAx5RxdF6\
He87NwC8i-hLBhugIvLTiDj-Sk9HvMth6zaD0ebxd56wDjq8-CMG_WcgusDqNzKFHqWNDHBXt8MLeTgZAR2rQMIMFZqFgsJlRflbig8YewmNUA9wAU74\
TfxLY1foO7Xpg49vceB7C-PlvGi1VtX6F2i0tc_67lA5kWXnnKBPBUyspoIrmAUCwfms5nTTqA9xXAojMhRHAos_OdM",
"expires_in":3600,
"token_type":"Bearer",
"scope":"api.secrets",
"encrypted_payload":"2.E9fE8+M/VWMfhhim1KlCbQ==|eLsHR484S/tJbIkM6spnG/HP65tj9A6Tba7kAAvUp+rYuQmGLixiOCfMsqt5OvBctDfvvr/Aes\
Bu7cZimPLyOEhqEAjn52jF0eaI38XZfeOG2VJl0LOf60Wkfh3ryAMvfvLj3G4ZCNYU8sNgoC2+IQ==|lNApuCQ4Pyakfo/wwuuajWNaEX/2MW8/3rjXB/V7n+k="})
)),
Mock::given(matchers::path("/api/organizations/f4e44a7f-1190-432a-9d4a-af96013127cb/secrets"))
.respond_with(ResponseTemplate::new(200).set_body_json(
serde_json::json!({
"secrets":[{
"id":"15744a66-341a-4c62-af50-af960166b6bc",
"organizationId":"f4e44a7f-1190-432a-9d4a-af96013127cb",
"key":"2.pMS6/icTQABtulw52pq2lg==|XXbxKxDTh+mWiN1HjH2N1w==|Q6PkuT+KX/axrgN9ubD5Ajk2YNwxQkgs3WJM0S0wtG8=",
"creationDate":"2023-01-26T21:46:02.2182556Z",
"revisionDate":"2023-01-26T21:46:02.2182557Z"
}],
"projects":[],
"object":"SecretsWithProjectsList"
})
)),
Mock::given(matchers::path("/api/secrets/15744a66-341a-4c62-af50-af960166b6bc"))
.respond_with(ResponseTemplate::new(200).set_body_json(
serde_json::json!({
"id":"15744a66-341a-4c62-af50-af960166b6bc",
"organizationId":"f4e44a7f-1190-432a-9d4a-af96013127cb",
"key":"2.pMS6/icTQABtulw52pq2lg==|XXbxKxDTh+mWiN1HjH2N1w==|Q6PkuT+KX/axrgN9ubD5Ajk2YNwxQkgs3WJM0S0wtG8=",
"value":"2.Gl34n9JYABC7V21qHcBzHg==|c1Ds244pob7i+8+MXe4++w==|Shimz/qKMYZmzSFWdeBzFb9dFz7oF6Uv9oqkws7rEe0=",
"note":"2.Cn9ABJy7+WfR4uUHwdYepg==|+nbJyU/6hSknoa5dcEJEUg==|1DTp/ZbwGO3L3RN+VMsCHz8XDr8egn/M5iSitGGysPA=",
"creationDate":"2023-01-26T21:46:02.2182556Z",
"revisionDate":"2023-01-26T21:46:02.2182557Z",
"object":"secret"
})
))
]).await;

// Test the login is correct and we store the returned organization ID correctly
let res = client
.auth()
.login_access_token(&AccessTokenLoginRequest {
access_token: "0.ec2c1d46-6a4b-4751-a310-af9601317f2d.C2IgxjjLF7qSshsbwe8JGcbM075YXw:X8vbvA0bduihIDe/qrzIQQ==".into(),
})
.await
.unwrap();
assert!(res.authenticated);
let organization_id = client.get_access_token_organization().unwrap();
assert_eq!(
organization_id.to_string(),
"f4e44a7f-1190-432a-9d4a-af96013127cb"
);

// Test that we can retrieve the list of secrets correctly
let mut res = client
.secrets()
.list(&SecretIdentifiersRequest { organization_id })
.await
.unwrap();
assert_eq!(res.data.len(), 1);

// Test that given a secret ID we can get it's data
let res = client
.secrets()
.get(&SecretGetRequest {
id: res.data.remove(0).id,
})
.await
.unwrap();
assert_eq!(res.key, "TEST");
assert_eq!(res.note, "TEST");
assert_eq!(res.value, "TEST");
}
}
2 changes: 1 addition & 1 deletion crates/bitwarden/src/auth/login/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
Client,
};

pub(crate) async fn access_token_login(
pub(crate) async fn login_access_token(
client: &mut Client,
input: &AccessTokenLoginRequest,
) -> Result<AccessTokenLoginResponse> {
Expand Down
4 changes: 2 additions & 2 deletions crates/bitwarden/src/auth/login/api_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
Client,
};

pub(crate) async fn api_key_login(
pub(crate) async fn login_api_key(
client: &mut Client,
input: &ApiKeyLoginRequest,
) -> Result<ApiKeyLoginResponse> {
Expand All @@ -30,7 +30,7 @@ pub(crate) async fn api_key_login(
.email
.ok_or(Error::Internal("Access token doesn't contain email"))?;

let kdf = client.prelogin(email.clone()).await?;
let kdf = client.auth().prelogin(email.clone()).await?;

client.set_tokens(
r.access_token.clone(),
Expand Down
6 changes: 3 additions & 3 deletions crates/bitwarden/src/auth/login/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub mod response;

mod password;
#[cfg(feature = "internal")]
pub(crate) use password::password_login;
pub(crate) use password::login_password;
#[cfg(feature = "internal")]
pub use password::PasswordLoginRequest;
pub use password::PasswordLoginResponse;
Expand All @@ -28,14 +28,14 @@ pub use two_factor::{TwoFactorEmailRequest, TwoFactorProvider, TwoFactorRequest}
#[cfg(feature = "internal")]
mod api_key;
#[cfg(feature = "internal")]
pub(crate) use api_key::api_key_login;
pub(crate) use api_key::login_api_key;
#[cfg(feature = "internal")]
pub use api_key::{ApiKeyLoginRequest, ApiKeyLoginResponse};

#[cfg(feature = "secrets")]
mod access_token;
#[cfg(feature = "secrets")]
pub(crate) use access_token::access_token_login;
pub(super) use access_token::login_access_token;
#[cfg(feature = "secrets")]
pub use access_token::{AccessTokenLoginRequest, AccessTokenLoginResponse};

Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden/src/auth/login/password.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
};

#[cfg(feature = "internal")]
pub(crate) async fn password_login(
pub(crate) async fn login_password(
client: &mut Client,
input: &PasswordLoginRequest,
) -> Result<PasswordLoginResponse> {
Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden/src/auth/login/two_factor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) async fn send_two_factor_email(
input: &TwoFactorEmailRequest,
) -> Result<()> {
// TODO: This should be resolved from the client
let kdf = client.prelogin(input.email.clone()).await?;
let kdf = client.auth().prelogin(input.email.clone()).await?;

let password_hash = determine_password_hash(&input.email, &kdf, &input.password).await?;

Expand Down
1 change: 0 additions & 1 deletion crates/bitwarden/src/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pub(super) mod api;
#[cfg(feature = "internal")]
pub mod client_auth;
mod jwt_token;
pub mod login;
Expand Down
Loading

0 comments on commit 5d9e997

Please sign in to comment.