auth: widen identity provider seam

This commit is contained in:
github-ops
2026-05-15 06:09:34 +00:00
parent c28f07901a
commit a1e90585b1
6 changed files with 128 additions and 12 deletions
Generated
+10 -10
View File
@@ -4,7 +4,7 @@ version = 4
[[package]]
name = "admin-api"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"argon2",
"async-trait",
@@ -384,7 +384,7 @@ dependencies = [
[[package]]
name = "crank-adapter-rest"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"async-trait",
"axum",
@@ -399,7 +399,7 @@ dependencies = [
[[package]]
name = "crank-community-auth"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"argon2",
"async-trait",
@@ -417,7 +417,7 @@ dependencies = [
[[package]]
name = "crank-community-mcp"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"async-trait",
"axum",
@@ -440,7 +440,7 @@ dependencies = [
[[package]]
name = "crank-core"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"async-trait",
"serde",
@@ -453,7 +453,7 @@ dependencies = [
[[package]]
name = "crank-mapping"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"crank-core",
"serde",
@@ -464,7 +464,7 @@ dependencies = [
[[package]]
name = "crank-registry"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"crank-core",
"crank-mapping",
@@ -480,7 +480,7 @@ dependencies = [
[[package]]
name = "crank-runtime"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"aes-gcm",
"async-trait",
@@ -505,7 +505,7 @@ dependencies = [
[[package]]
name = "crank-schema"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"crank-core",
"serde",
@@ -1273,7 +1273,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "mcp-server"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"async-trait",
"axum",
+1 -1
View File
@@ -17,7 +17,7 @@ resolver = "3"
edition = "2024"
license = "MIT"
rust-version = "1.85"
version = "0.2.0"
version = "0.3.0"
[workspace.dependencies]
aes-gcm = "0.10"
+1
View File
@@ -163,4 +163,5 @@ Progress:
- Phase 1 / task `1.5`: создан crate `crank-community-mcp`; в него вынесены `build_app`, `catalog`, `jsonrpc`, `session` и `auth` из `apps/mcp-server`, а `apps/mcp-server/src/main.rs` стал thin launcher с env parsing и DI wiring
- Phase 1 / task `1.6`: Community test surface уже приведен к честному baseline — `test = false` удален ранее, premium-only tests вычищены, `just verify` проходит на текущем составе workspace
- Phase 1 / task `1.7`: workspace version bumped to `0.2.0`; release gate пройден (`just verify`, `npm run build`, `npm run e2e`), release commit и tag `v0.2.0` подготовлены в `crank-community`
- Phase 2 dependency slice: `IdentityProvider` seam widened to cover `SSO/TOTP` with default `NotSupportedForProvider` methods and shared public DTOs for authorize/callback/two-factor flows; workspace version bumped to `0.3.0` for downstream enterprise consumption
- backward-compatible alias `CommunityMachineCredentialVerifier` сохранен, поведение Community не изменено
+3
View File
@@ -912,6 +912,9 @@ impl AdminService {
.await
{
Ok(LoginOutcome::Authenticated(identity)) => Ok(identity),
Ok(LoginOutcome::TwoFactorRequired(_)) => Err(ApiError::internal(
"two-factor login flow is not configured for this service",
)),
Err(error) => Err(map_identity_error(error)),
};
}
+110
View File
@@ -1,6 +1,7 @@
use std::sync::Arc;
use async_trait::async_trait;
use time::OffsetDateTime;
use crate::{
IssueAgentTokenRequest, IssueOneTimeAgentTokenRequest, IssuedAgentTokenResponse,
@@ -125,8 +126,64 @@ pub struct LoginPayload {
pub password: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SsoAuthorizeRequest {
pub workspace_id: WorkspaceId,
pub provider_id: String,
pub base_origin: String,
pub return_to: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SsoAuthorizeRedirect {
pub authorization_url: String,
pub state: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SsoCallbackRequest {
pub workspace_id: WorkspaceId,
pub provider_id: String,
pub code: String,
pub base_origin: String,
pub return_to: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TwoFactorPendingIdentity {
pub user_id: UserId,
pub workspace_id: Option<WorkspaceId>,
pub return_to: Option<String>,
pub expires_at: OffsetDateTime,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TwoFactorStatus {
pub enabled: bool,
pub pending_setup: bool,
pub recovery_codes_remaining: usize,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TwoFactorSetup {
pub secret: String,
pub otpauth_url: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TwoFactorActivation {
pub recovery_codes: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct TwoFactorChallenge {
pub code: Option<String>,
pub recovery_code: Option<String>,
}
pub enum LoginOutcome {
Authenticated(AuthenticatedIdentity),
TwoFactorRequired(TwoFactorPendingIdentity),
}
#[async_trait]
@@ -136,6 +193,59 @@ pub trait IdentityProvider: Send + Sync {
fn kind(&self) -> IdentityProviderKind;
async fn login_password(&self, payload: LoginPayload) -> Result<LoginOutcome, IdentityError>;
async fn begin_sso(
&self,
_request: SsoAuthorizeRequest,
) -> Result<SsoAuthorizeRedirect, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn complete_sso(
&self,
_request: SsoCallbackRequest,
) -> Result<LoginOutcome, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn get_two_factor_status(
&self,
_user_id: &UserId,
) -> Result<TwoFactorStatus, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn begin_two_factor_setup(
&self,
_user_id: &UserId,
_email: &str,
) -> Result<TwoFactorSetup, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn activate_two_factor(
&self,
_user_id: &UserId,
_code: &str,
) -> Result<TwoFactorActivation, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn disable_two_factor(
&self,
_user_id: &UserId,
_challenge: TwoFactorChallenge,
) -> Result<(), IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
async fn verify_two_factor_login(
&self,
_pending: &TwoFactorPendingIdentity,
_challenge: TwoFactorChallenge,
) -> Result<AuthenticatedIdentity, IdentityError> {
Err(IdentityError::NotSupportedForProvider)
}
}
pub type SharedIdentityProvider = Arc<dyn IdentityProvider>;
+3 -1
View File
@@ -43,7 +43,9 @@ pub use ext::auth::{
AuthenticatedIdentity, IdentityError, IdentityProvider, IdentityProviderKind, LoginOutcome,
LoginPayload, MachineCredentialVerifier, MachineCredentialVerifierError, MachineTokenIssuer,
NoMachineTokenIssuer, SharedIdentityProvider, SharedMachineCredentialVerifier,
SharedMachineTokenIssuer, TokenIssuerActor, TokenIssuerError, VerifiedMachineCredential,
SharedMachineTokenIssuer, SsoAuthorizeRedirect, SsoAuthorizeRequest, SsoCallbackRequest,
TokenIssuerActor, TokenIssuerError, TwoFactorActivation, TwoFactorChallenge,
TwoFactorPendingIdentity, TwoFactorSetup, TwoFactorStatus, VerifiedMachineCredential,
};
pub use ext::capability::{CapabilityProfile, CommunityCapabilityProfile};
pub use ext::protocol::{