Skip to main content

krabka_security/
lib.rs

1//! Security primitives used by Krabka brokers, clients, and tooling.
2//!
3//! The crate owns the protocol-independent pieces of TLS, SASL, SCRAM,
4//! OAuth/OIDC, mTLS principal extraction, delegation-token HMACs, Kerberos
5//! exchange state, and principal modelling. Network I/O stays in the caller.
6//! The async [`IntrospectionClient`] trait represents OAuth introspection, and
7//! the broker and client crates supply the concrete transports and wire the
8//! resulting validators into listener or connection handshakes.
9//!
10//! ## SASL/PLAIN verification
11//!
12//! ```rust
13//! use std::collections::HashMap;
14//!
15//! use krabka_security::{AuthMethod, verify_plain};
16//!
17//! let mut users = HashMap::new();
18//! users.insert("alice".to_string(), "wonderland".to_string());
19//!
20//! let principal = verify_plain(&users, "alice", b"wonderland").unwrap();
21//! assert_eq!(principal.name, "alice");
22//! assert_eq!(principal.auth_method, AuthMethod::SaslPlain);
23//! ```
24//!
25//! ## Storing SCRAM credentials
26//!
27//! ```rust
28//! use krabka_security::{SaslMechanism, hash_scram_password};
29//!
30//! let credential = hash_scram_password(
31//!     b"correct horse battery staple",
32//!     SaslMechanism::ScramSha512,
33//!     4096,
34//! )?;
35//! assert_eq!(credential.iterations, 4096);
36//! # Ok::<_, krabka_security::ScramError>(())
37//! ```
38//!
39//! ## Cargo features
40//!
41//! - `gssapi` (off by default): SASL/GSSAPI (Kerberos), the `gssapi` module.
42//!   It is native-only, and has no effect on `wasm32` targets.
43//!
44//! `gssapi` stays out of `default` on purpose. The Kerberos stack it pulls in,
45//! `sspi`, depends on `rsa` 0.10, which carries RUSTSEC-2023-0071 (the
46//! Marvin timing side channel) and has no patched release. A build without the
47//! feature compiles no `rsa` at all. A build with it is still not exposed,
48//! because Krabka's GSSAPI path uses only AES keytab keys and never
49//! runs an RSA private-key operation; `docs/rustsec-2023-0071.md` in the
50//! repository gives the reachability analysis.
51//!
52//! Without the feature, [`SaslMechanism::Gssapi`] still parses and still names
53//! the mechanism in persisted metadata, but [`SaslMechanism::is_available`]
54//! returns `false` for it and [`SaslMechanism::require_available`] returns
55//! [`AuthError::UnsupportedMechanism`]. A broker maps that to Kafka's
56//! `UNSUPPORTED_SASL_MECHANISM` (error code 33) in the `SaslHandshake` response,
57//! and a client reports it before it opens a connection.
58
59pub mod ca;
60pub mod delegation_token;
61#[cfg(all(feature = "gssapi", not(target_family = "wasm")))]
62pub mod gssapi;
63pub mod java_regex;
64mod jwks;
65mod jwks_trust;
66mod listener;
67mod mechanism;
68mod mtls;
69mod oauthbearer;
70mod plain;
71mod principal;
72mod reload;
73pub mod scram;
74mod tls;
75
76pub use delegation_token::{SecretBytes, compute_token_hmac};
77pub use jwks::{Jwks, JwksHandle};
78pub use jwks_trust::{JwksTrustError, build_client_config_from_pem};
79pub use listener::ListenerProtocol;
80pub use mechanism::SaslMechanism;
81pub use mtls::extract_principal_from_cert;
82pub use oauthbearer::{
83    AuthOutcome, ClientInitialResponse, IntrospectionClient, IntrospectionError,
84    IntrospectionValidator, InvalidScopeItem, OAuthBearerValidator, SignedJwsValidator,
85    UnsecuredJwsValidator, oauth_error_json, parse_client_initial_response, parse_required_scope,
86};
87pub use plain::verify_plain;
88pub use principal::{AuthError, AuthMethod, KafkaPrincipal, Principal};
89pub use reload::DynamicServerConfig;
90pub use scram::{
91    ScramClientExchange, ScramClientFirst, ScramCredential, ScramError, ScramServerExchange,
92    StepResult, TOKEN_AUTH_EXTENSION, decode_saslname, derive_keys_from_salted, encode_saslname,
93    hash_scram_password, pbkdf2_salted, scram_hash_len,
94};
95pub use tls::{ClientAuthMode, TlsConfig, TlsError};