Skip to main content

sipx_call/
identity.rs

1//! Caller-owned authenticated-identity policies for live calls.
2//!
3//! The cryptographic services live in `sipx-ua`; this module only composes them with call
4//! establishment. Time, authority, credentials, retrieval and trust all remain values supplied by
5//! the application.
6
7use std::fmt;
8use std::sync::Arc;
9
10use sipx_sip::Request;
11use sipx_ua::identity::{
12    AuthenticationError, AuthenticationService, Authority, CredentialFetcher, VerificationFailure,
13    VerificationService,
14};
15
16trait SignCall: Send + Sync {
17    fn sign(&self, request: &mut Request) -> Result<(), AuthenticationError>;
18}
19
20struct SelectedAuthentication<A, N> {
21    service: AuthenticationService<A>,
22    now: N,
23}
24
25impl<A, N> SignCall for SelectedAuthentication<A, N>
26where
27    A: Authority + Send + Sync,
28    N: Fn() -> i64 + Send + Sync,
29{
30    fn sign(&self, request: &mut Request) -> Result<(), AuthenticationError> {
31        self.service.sign(request, (self.now)())
32    }
33}
34
35/// Authentication-service selection for an outbound call.
36///
37/// The caller supplies both the already configured service and the function that reads its notion
38/// of current Unix time. Constructing a policy performs no authority check and reads no clock;
39/// those inputs are used only when an INVITE attempt is about to be sent.
40#[derive(Clone)]
41pub struct OutboundIdentityPolicy {
42    signer: Arc<dyn SignCall>,
43}
44
45impl OutboundIdentityPolicy {
46    /// Select an authentication service and a caller-owned time source.
47    #[must_use]
48    pub fn new<A, N>(service: AuthenticationService<A>, now: N) -> Self
49    where
50        A: Authority + Send + Sync + 'static,
51        N: Fn() -> i64 + Send + Sync + 'static,
52    {
53        Self {
54            signer: Arc::new(SelectedAuthentication { service, now }),
55        }
56    }
57
58    pub(crate) fn sign(&self, request: &mut Request) -> Result<(), AuthenticationError> {
59        self.signer.sign(request)
60    }
61}
62
63impl fmt::Debug for OutboundIdentityPolicy {
64    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
65        formatter
66            .debug_struct("OutboundIdentityPolicy")
67            .finish_non_exhaustive()
68    }
69}
70
71trait VerifyCall: Send + Sync {
72    fn verify(&mut self, request: &Request) -> Result<(), VerificationFailure>;
73}
74
75struct SelectedVerification<S, N> {
76    service: VerificationService<S>,
77    now: N,
78    required: bool,
79}
80
81impl<S, N> VerifyCall for SelectedVerification<S, N>
82where
83    S: CredentialFetcher + Send + Sync,
84    N: Fn() -> i64 + Send + Sync,
85{
86    fn verify(&mut self, request: &Request) -> Result<(), VerificationFailure> {
87        self.service
88            .verify(request, (self.now)(), self.required)
89            .map(|_| ())
90    }
91}
92
93/// Verification-service selection for inbound calls handled by a dispatcher.
94///
95/// The policy owns the service because its bounded credential cache is stateful. `required`
96/// decides whether an INVITE without a usable `Identity` is refused with 428 or surfaced as an
97/// unverified ordinary call. The time function and the service's credential fetcher are both
98/// caller-owned; the call layer performs neither clock nor network I/O for them.
99pub struct InboundIdentityPolicy {
100    verifier: Box<dyn VerifyCall>,
101}
102
103impl InboundIdentityPolicy {
104    /// Select a verification service, missing-identity policy, and caller-owned time source.
105    #[must_use]
106    pub fn new<S, N>(service: VerificationService<S>, required: bool, now: N) -> Self
107    where
108        S: CredentialFetcher + Send + Sync + 'static,
109        N: Fn() -> i64 + Send + Sync + 'static,
110    {
111        Self {
112            verifier: Box::new(SelectedVerification {
113                service,
114                now,
115                required,
116            }),
117        }
118    }
119
120    pub(crate) fn verify(&mut self, request: &Request) -> Result<(), VerificationFailure> {
121        self.verifier.verify(request)
122    }
123}
124
125impl fmt::Debug for InboundIdentityPolicy {
126    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
127        formatter
128            .debug_struct("InboundIdentityPolicy")
129            .finish_non_exhaustive()
130    }
131}