74 lines
2.0 KiB
Rust
74 lines
2.0 KiB
Rust
use async_trait::async_trait;
|
|
use crank_core::{
|
|
AuthenticatedIdentity, IdentityError, IdentityProvider, IdentityProviderKind, LoginOutcome,
|
|
};
|
|
use crank_registry::PostgresRegistry;
|
|
use tracing::debug;
|
|
|
|
use crate::hashing::verify_password;
|
|
|
|
#[derive(Clone)]
|
|
pub struct PasswordIdentityProvider {
|
|
registry: PostgresRegistry,
|
|
password_pepper: String,
|
|
}
|
|
|
|
impl PasswordIdentityProvider {
|
|
pub fn new(registry: PostgresRegistry, password_pepper: impl Into<String>) -> Self {
|
|
Self {
|
|
registry,
|
|
password_pepper: password_pepper.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl IdentityProvider for PasswordIdentityProvider {
|
|
fn id(&self) -> &str {
|
|
"community-password"
|
|
}
|
|
|
|
fn kind(&self) -> IdentityProviderKind {
|
|
IdentityProviderKind::Password
|
|
}
|
|
|
|
async fn login_password(
|
|
&self,
|
|
payload: crank_core::LoginPayload,
|
|
) -> Result<LoginOutcome, IdentityError> {
|
|
let user = self
|
|
.registry
|
|
.get_auth_user_by_email(&payload.email)
|
|
.await
|
|
.map_err(|error| IdentityError::Internal(error.to_string()))?
|
|
.ok_or(IdentityError::BadCredentials)?;
|
|
|
|
if user.user.status != crank_core::UserStatus::Active {
|
|
return Err(IdentityError::AccountDisabled);
|
|
}
|
|
|
|
if !verify_password(
|
|
&payload.password,
|
|
&self.password_pepper,
|
|
&user.password_hash,
|
|
) {
|
|
debug!(email = %payload.email, "password identity provider rejected credentials");
|
|
return Err(IdentityError::BadCredentials);
|
|
}
|
|
|
|
let current_workspace_id = self
|
|
.registry
|
|
.list_workspaces_for_user(&user.user.id)
|
|
.await
|
|
.map_err(|error| IdentityError::Internal(error.to_string()))?
|
|
.first()
|
|
.map(|membership| membership.workspace.id.clone());
|
|
|
|
Ok(LoginOutcome::Authenticated(AuthenticatedIdentity {
|
|
user: user.user,
|
|
memberships: vec![],
|
|
current_workspace_id,
|
|
}))
|
|
}
|
|
}
|