Skip to content
Clone
ef0b83a
509 lines 16.2 KB Rust
use async_trait::async_trait;
use export::{AuthApi, KenAuthError};
use tonic::Request;
use crate::AuthService;
use crate::api::context::RequestMeta;
use crate::protos::auth as proto;
use crate::protos::auth::internal::v1::authority_service_server::AuthorityService;
use crate::protos::auth::v1::identity_service_server::IdentityService;
use crate::protos::auth::v1::mfa_service_server::MfaService;
use crate::protos::auth::v1::session_service_server::SessionService;
use crate::protos::auth::v1::ssh_key_service_server::SshKeyService;
pub mod authority;
pub mod context;
pub mod convert;
pub mod error;
pub mod identity;
pub mod mfa;
pub mod session;
pub mod ssh_key;
pub mod store;
impl AuthService {
fn identity(&self) -> crate::api::identity::IdentityApi {
crate::api::identity::IdentityApi::new(self.clone())
}
fn authority(&self) -> crate::api::authority::AuthorityApi {
crate::api::authority::AuthorityApi::new(self.clone())
}
fn session(&self) -> crate::api::session::SessionApi {
crate::api::session::SessionApi::new(self.clone())
}
fn ssh_key(&self) -> crate::api::ssh_key::SshKeyApi {
crate::api::ssh_key::SshKeyApi::new(self.clone())
}
fn mfa(&self) -> crate::api::mfa::MfaApi {
crate::api::mfa::MfaApi::new(self.clone())
}
pub fn read_request<T>(&self, message: T) -> Request<T> {
let mut request = Request::new(message);
request.set_timeout(self.read_timeout);
request.extensions_mut().insert(RequestMeta::internal());
request
}
pub fn write_request<T>(&self, message: T) -> Request<T> {
let mut request = Request::new(message);
request.set_timeout(self.write_timeout);
request.extensions_mut().insert(RequestMeta::internal());
request
}
}
#[async_trait]
impl AuthApi for AuthService {
async fn check_health(&self) -> Result<(), KenAuthError> {
self.cache()
.ping()
.await
.map_err(|error| KenAuthError::Unavailable(error.to_string()))
}
#[allow(clippy::too_many_arguments)]
async fn change_password(
&self,
user_id: i64,
old_password_hash: &str,
new_password_hash: &str,
keep_session_id: &str,
client_ip: &str,
) -> Result<proto::v1::ChangePasswordResponse, KenAuthError> {
let client = self.identity();
client
.change_password(self.write_request(proto::v1::ChangePasswordRequest {
user_id,
old_password_hash: old_password_hash.to_string(),
new_password_hash: new_password_hash.to_string(),
keep_session_id: keep_session_id.to_string(),
client_ip: client_ip.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn get_mfa_status(
&self,
user_id: i64,
) -> Result<proto::v1::GetMfaStatusResponse, KenAuthError> {
let client = self.mfa();
client
.get_mfa_status(self.read_request(proto::v1::GetMfaStatusRequest { user_id }))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn configure_totp(
&self,
user_id: i64,
name: &str,
client_ip: &str,
) -> Result<proto::v1::ConfigureTotpResponse, KenAuthError> {
let client = self.mfa();
client
.configure_totp(self.write_request(proto::v1::ConfigureTotpRequest {
user_id,
name: name.to_string(),
client_ip: client_ip.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn enable_totp(
&self,
user_id: i64,
code: &str,
password_hash: &str,
client_ip: &str,
) -> Result<proto::v1::EnableTotpResponse, KenAuthError> {
let client = self.mfa();
client
.enable_totp(self.write_request(proto::v1::EnableTotpRequest {
user_id,
code: code.to_string(),
password_hash: password_hash.to_string(),
client_ip: client_ip.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn disable_totp(
&self,
user_id: i64,
code: &str,
client_ip: &str,
) -> Result<proto::v1::DisableTotpResponse, KenAuthError> {
let client = self.mfa();
client
.disable_totp(self.write_request(proto::v1::DisableTotpRequest {
user_id,
code: code.to_string(),
client_ip: client_ip.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn regenerate_recovery_codes(
&self,
user_id: i64,
password_hash: &str,
client_ip: &str,
) -> Result<proto::v1::RegenerateRecoveryCodesResponse, KenAuthError> {
let client = self.mfa();
client
.regenerate_recovery_codes(self.write_request(
proto::v1::RegenerateRecoveryCodesRequest {
user_id,
password_hash: password_hash.to_string(),
client_ip: client_ip.to_string(),
},
))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
#[allow(clippy::too_many_arguments)]
async fn list_user_ssh_keys(
&self,
user_id: i64,
include_revoked: bool,
page: proto::common::v1::PageRequest,
) -> Result<proto::v1::ListUserSshKeysResponse, KenAuthError> {
let client = self.ssh_key();
client
.list_user_ssh_keys(self.read_request(proto::v1::ListUserSshKeysRequest {
user_id,
include_revoked,
page: Some(page),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn add_ssh_key(
&self,
user_id: i64,
name: &str,
public_key: &str,
description: &str,
client_ip: &str,
) -> Result<proto::v1::AddSshKeyResponse, KenAuthError> {
let client = self.ssh_key();
client
.add_ssh_key(self.write_request(proto::v1::AddSshKeyRequest {
user_id,
name: name.to_string(),
public_key: public_key.to_string(),
description: description.to_string(),
client_ip: client_ip.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn revoke_ssh_key(
&self,
user_id: i64,
key_id: &str,
reason: &str,
bump_security_version: bool,
) -> Result<proto::v1::RevokeSshKeyResponse, KenAuthError> {
let client = self.ssh_key();
client
.revoke_ssh_key(self.write_request(proto::v1::RevokeSshKeyRequest {
user_id,
key_id: key_id.to_string(),
reason: reason.to_string(),
bump_security_version,
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn list_user_sessions(
&self,
user_id: i64,
include_revoked: bool,
include_expired: bool,
page: proto::common::v1::PageRequest,
) -> Result<proto::v1::ListUserSessionsResponse, KenAuthError> {
let client = self.session();
client
.list_user_sessions(self.read_request(proto::v1::ListUserSessionsRequest {
user_id,
include_revoked,
include_expired,
page: Some(page),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn revoke_user_sessions(
&self,
user_id: i64,
except_session_id: &str,
reason: &str,
bump_security_version: bool,
) -> Result<proto::v1::RevokeUserSessionsResponse, KenAuthError> {
let client = self.session();
client
.revoke_user_sessions(self.write_request(proto::v1::RevokeUserSessionsRequest {
user_id,
except_session_id: except_session_id.to_string(),
reason: reason.to_string(),
bump_security_version,
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner())
}
async fn get_session(
&self,
user_id: i64,
version: i32,
session_id: &str,
) -> Result<proto::internal::v1::AuthorityAccess, KenAuthError> {
let client = self.authority();
client
.get_session(self.read_request(proto::internal::v1::GetSessionRequest {
user_id,
version,
session_id: session_id.to_string(),
}))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner().access.unwrap_or_default())
}
async fn delete_account(&self, user_id: i64, reason: &str) -> Result<(), KenAuthError> {
let client = self.authority();
client
.delete_account(
self.write_request(proto::internal::v1::DeleteAccountRequest {
user_id,
reason: reason.to_string(),
}),
)
.await
.map_err(KenAuthError::from_status)?;
Ok(())
}
async fn cancel_account_deletion(&self, user_id: i64) -> Result<(), KenAuthError> {
let client = self.authority();
client
.cancel_account_deletion(
self.write_request(proto::internal::v1::CancelAccountDeletionRequest { user_id }),
)
.await
.map_err(KenAuthError::from_status)?;
Ok(())
}
async fn purge_account(&self, user_id: i64) -> Result<(), KenAuthError> {
let client = self.authority();
client
.purge_account(self.write_request(proto::internal::v1::PurgeAccountRequest { user_id }))
.await
.map_err(KenAuthError::from_status)?;
Ok(())
}
async fn batch_get_authority_users(
&self,
user_ids: Vec<i64>,
) -> Result<Vec<proto::internal::v1::AuthorityUser>, KenAuthError> {
let client = self.authority();
client
.batch_get_user(
self.read_request(proto::internal::v1::BatchGetUserRequest { user_ids }),
)
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner().users)
}
async fn get_user_status(
&self,
user_id: i64,
) -> Result<proto::common::v1::UserStatus, KenAuthError> {
let client = self.identity();
let user = Some(proto::common::v1::UserRef {
key: Some(proto::common::v1::user_ref::Key::UserId(user_id)),
});
client
.get_user_status(self.read_request(proto::v1::GetUserStatusRequest { user }))
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner().status.unwrap_or_default())
}
async fn get_user_public_by_ref(
&self,
key: proto::common::v1::user_ref::Key,
) -> Result<proto::common::v1::UserPublic, KenAuthError> {
let client = self.identity();
let user = Some(proto::common::v1::UserRef { key: Some(key) });
client
.get_user_public(self.read_request(proto::v1::GetUserPublicRequest { user }))
.await
.map_err(KenAuthError::from_status)?
.into_inner()
.user
.ok_or(KenAuthError::NotFound)
}
async fn get_authority_user(
&self,
user_id: i64,
) -> Result<proto::internal::v1::AuthorityUser, KenAuthError> {
let client = self.authority();
client
.get_user(self.read_request(proto::internal::v1::GetUserRequest { user_id }))
.await
.map_err(KenAuthError::from_status)?
.into_inner()
.user
.ok_or(KenAuthError::NotFound)
}
#[allow(clippy::too_many_arguments)]
async fn update_authority_user(
&self,
user_id: i64,
username: Option<String>,
displayname: Option<String>,
clear_displayname: bool,
public_show_email: Option<bool>,
version: i32,
) -> Result<proto::internal::v1::AuthorityUser, KenAuthError> {
let client = self.authority();
client
.update_user(self.write_request(proto::internal::v1::UpdateUserRequest {
user_id,
patch: Some(proto::internal::v1::AuthorityUserPatch {
version,
username,
displayname,
clear_displayname,
public_show_email,
}),
}))
.await
.map_err(KenAuthError::from_status)?
.into_inner()
.user
.ok_or(KenAuthError::NotFound)
}
async fn batch_get_user_public(
&self,
user_ids: Vec<i64>,
) -> Result<Vec<proto::common::v1::UserPublic>, KenAuthError> {
let client = self.identity();
client
.batch_get_user_public(
self.read_request(proto::v1::BatchGetUserPublicRequest { user_ids }),
)
.await
.map_err(KenAuthError::from_status)
.map(|response| response.into_inner().users)
}
async fn get_user_public(
&self,
user_id: i64,
) -> Result<proto::common::v1::UserPublic, KenAuthError> {
let client = self.identity();
let user = Some(proto::common::v1::UserRef {
key: Some(proto::common::v1::user_ref::Key::UserId(user_id)),
});
client
.get_user_public(self.read_request(proto::v1::GetUserPublicRequest { user }))
.await
.map_err(KenAuthError::from_status)?
.into_inner()
.user
.ok_or(KenAuthError::NotFound)
}
async fn revoke_session(
&self,
user_id: i64,
session_id: &str,
reason: &str,
) -> Result<(), KenAuthError> {
let client = self.session();
client
.revoke_session(self.write_request(proto::v1::RevokeSessionRequest {
user_id,
session_id: session_id.to_string(),
reason: reason.to_string(),
}))
.await
.map_err(KenAuthError::from_status)?;
Ok(())
}
async fn lookup_ssh_key(
&self,
public_key: &str,
) -> Result<Option<proto::common::v1::Principal>, KenAuthError> {
let client = self.ssh_key();
let response = client
.lookup_ssh_key(self.read_request(proto::v1::LookupSshKeyRequest {
fingerprint: String::new(),
public_key: public_key.to_string(),
require_active: true,
}))
.await
.map_err(KenAuthError::from_status)?
.into_inner();
if !response.found {
return Ok(None);
}
Ok(response.principal)
}
async fn ensure_bot_user(
&self,
username: &str,
displayname: &str,
system: bool,
) -> Result<proto::common::v1::UserPublic, KenAuthError> {
let client = self.identity();
client
.ensure_bot_user(self.write_request(proto::v1::EnsureBotUserRequest {
username: username.to_string(),
displayname: displayname.to_string(),
system,
}))
.await
.map_err(KenAuthError::from_status)?
.into_inner()
.user
.ok_or(KenAuthError::NotFound)
}
}