### Rust Cross-KRB5 Client-Server Authentication Source: https://context7.com/estokes/cross-krb5/llms.txt This example demonstrates mutual authentication and encrypted message exchange between client and server threads. It requires a service principal name as a command-line argument. Ensure you have a Kerberos environment set up. ```rust use bytes::Bytes; use cross_krb5::{AcceptFlags, ClientCtx, InitiateFlags, K5Ctx, K5ServerCtx, ServerCtx, Step}; use std::{env::args, process::exit, sync::mpsc, thread}; enum Msg { Token(Bytes), Msg(Bytes), } fn server(spn: String, input: mpsc::Receiver, output: mpsc::Sender) { // Initialize server context with service principal let mut server = ServerCtx::new(AcceptFlags::empty(), Some(&spn)).expect("server new"); // Complete authentication handshake let mut server = loop { let token = match input.recv().expect("recv token") { Msg::Msg(_) => panic!("server not initialized"), Msg::Token(t) => t, }; match server.step(&*token).expect("server step") { Step::Finished((ctx, token)) => { if let Some(token) = token { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); } break ctx; } Step::Continue((ctx, token)) => { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); server = ctx; } } }; // Receive and decrypt message from authenticated client match input.recv().expect("recv msg") { Msg::Token(_) => panic!("unexpected token"), Msg::Msg(encrypted) => { let decrypted = server.unwrap(&*encrypted).expect("unwrap"); println!("Server received: {}", String::from_utf8_lossy(&decrypted)); } } } fn client(spn: &str, input: mpsc::Receiver, output: mpsc::Sender) { // Initialize client context targeting the service let (mut client, token) = ClientCtx::new( InitiateFlags::empty(), None, // Use current user spn, None, ).expect("client new"); output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); // Complete authentication handshake let mut client = loop { let token = match input.recv().expect("recv token") { Msg::Msg(_) => panic!("client not initialized"), Msg::Token(t) => t, }; match client.step(&*token).expect("client step") { Step::Finished((ctx, token)) => { if let Some(token) = token { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); } break ctx; } Step::Continue((ctx, token)) => { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); client = ctx; } } }; // Send encrypted message to server let encrypted = client.wrap(true, b"Hello from authenticated client!").expect("wrap"); output.send(Msg::Msg(Bytes::copy_from_slice(&*encrypted))).expect("send"); } fn main() { let args: Vec<_> = args().collect(); if args.len() != 2 { println!("usage: {} ", args[0]); exit(1); } let spn = args[1].clone(); let (server_tx, server_rx) = mpsc::channel(); let (client_tx, client_rx) = mpsc::channel(); thread::spawn(move || server(spn, server_rx, client_tx)); client(&args[1], client_rx, server_tx); } // Run with: cargo run --example auth -- HTTP/myhost.example.com@EXAMPLE.COM ``` -------------------------------- ### Configure Client/Server Contexts with InitiateFlags and AcceptFlags Source: https://context7.com/estokes/cross-krb5/llms.txt Configure client and server contexts using flags for standard GSSAPI or Windows SSPI Negotiate token compatibility. ```rust use cross_krb5::{ClientCtx, ServerCtx, InitiateFlags, AcceptFlags}; fn windows_negotiate_compatibility() -> anyhow::Result<()> { // For Windows servers that expect SSPI Negotiate tokens instead of GSSAPI let (pending_client, token) = ClientCtx::new( InitiateFlags::NEGOTIATE_TOKEN, // Use SSPI Negotiate package None, "HTTP/windows-server.corp.local@CORP.LOCAL", None, )?; // For servers accepting from Windows clients sending Negotiate tokens let pending_server = ServerCtx::new( AcceptFlags::NEGOTIATE_TOKEN, // Accept SSPI Negotiate tokens Some("HTTP/myservice@CORP.LOCAL"), )?; // Standard cross-platform usage (GSSAPI compatible) let (standard_client, _) = ClientCtx::new( InitiateFlags::empty(), // Standard Kerberos tokens None, "service/host@REALM", None, )?; Ok(()) } ``` -------------------------------- ### Initiate Kerberos Client Authentication with Cross KRB5 Source: https://context7.com/estokes/cross-krb5/llms.txt Use ClientCtx::new to create a client context for initiating Kerberos authentication. This function requires the target service principal name (SPN) and returns an initial token to be sent to the server. The authentication handshake continues iteratively using the step method. ```rust use cross_krb5::{ClientCtx, InitiateFlags, Step, K5Ctx}; fn authenticate_client(target_spn: &str) -> anyhow::Result<()> { // Create a new client context - uses current user's credentials by default // target_spn format: "service/host@REALM" (e.g., "HTTP/server.example.com@EXAMPLE.COM") let (mut pending_client, initial_token) = ClientCtx::new( InitiateFlags::empty(), // Use default Kerberos behavior None, // Use current user's principal target_spn, // Target service principal name None, // No channel bindings )?; // Send initial_token to server, receive server_token back let server_token: Vec = send_to_server_and_receive(&initial_token)?; // Continue authentication handshake let client_ctx = loop { match pending_client.step(&server_token)? { Step::Finished((ctx, maybe_token)) => { if let Some(final_token) = maybe_token { send_to_server(&final_token)?; } break ctx; // Authentication complete } Step::Continue((ctx, token)) => { send_to_server(&token)?; let server_token = receive_from_server()?; pending_client = ctx; } } }; // Now use the authenticated context to send encrypted messages let encrypted_msg = client_ctx.wrap(true, b"Hello, secure world!")?; println!("Encrypted message length: {} bytes", encrypted_msg.len()); Ok(()) } ``` -------------------------------- ### Accept Kerberos Authentication as a Server with Cross KRB5 Source: https://context7.com/estokes/cross-krb5/llms.txt Use ServerCtx::new to create a server context for accepting Kerberos authentication. This requires the server's service principal name and processes client tokens iteratively. After successful authentication, it can decrypt messages from the client. ```rust use cross_krb5::{ServerCtx, AcceptFlags, Step, K5Ctx, K5ServerCtx}; fn handle_client_authentication(service_spn: &str, client_token: &[u8]) -> anyhow::Result<()> { // Create server context with the service's principal name let mut pending_server = ServerCtx::new( AcceptFlags::empty(), // Use default Kerberos behavior Some(service_spn), // Service principal (e.g., "HTTP/myserver@REALM") )?; // Process client tokens until authentication completes let mut current_token = client_token.to_vec(); let mut server_ctx = loop { match pending_server.step(¤t_token)? { Step::Finished((ctx, maybe_token)) => { if let Some(response_token) = maybe_token { send_to_client(&response_token)?; } break ctx; // Authentication successful } Step::Continue((ctx, response_token)) => { send_to_client(&response_token)?; current_token = receive_from_client()?; pending_server = ctx; } } }; // Get the authenticated client's principal name let client_name = server_ctx.client()?; println!("Authenticated client: {}", client_name); // Decrypt messages from the authenticated client let encrypted_data = receive_from_client()?; let decrypted = server_ctx.unwrap(&encrypted_data)?; println!("Received: {}", String::from_utf8_lossy(&decrypted)); Ok(()) } ``` -------------------------------- ### Implement Kerberos Authentication and Messaging in Rust Source: https://github.com/estokes/cross-krb5/blob/master/README.md Demonstrates a client-server interaction using cross-krb5 to establish a secure context and exchange encrypted messages. ```rust use bytes::Bytes; use cross_krb5::{AcceptFlags, ClientCtx, InitiateFlags, K5Ctx, Step, ServerCtx}; use std::{env::args, process::exit, sync::mpsc, thread}; enum Msg { Token(Bytes), Msg(Bytes), } fn server(spn: String, input: mpsc::Receiver, output: mpsc::Sender) { let mut server = ServerCtx::new(AcceptFlags::empty(), Some(&spn)).expect("new"); let mut server = loop { let token = match input.recv().expect("expected data") { Msg::Msg(_) => panic!("server not finished initializing"), Msg::Token(t) => t, }; match server.step(&*token).expect("step") { Step::Finished((ctx, token)) => { if let Some(token) = token { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); } break ctx }, Step::Continue((ctx, token)) => { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); server = ctx; } } }; match input.recv().expect("expected data msg") { Msg::Token(_) => panic!("unexpected extra token"), Msg::Msg(secret_msg) => println!( "{}", String::from_utf8_lossy(&server.unwrap(&*secret_msg).expect("unwrap")) ), } } fn client(spn: &str, input: mpsc::Receiver, output: mpsc::Sender) { let (mut client, token) = ClientCtx::new(InitiateFlags::empty(), None, spn, None).expect("new"); output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); let mut client = loop { let token = match input.recv().expect("expected data") { Msg::Msg(_) => panic!("client not finished initializing"), Msg::Token(t) => t, }; match client.step(&*token).expect("step") { Step::Finished((ctx, token)) => { if let Some(token) = token { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); } break ctx }, Step::Continue((ctx, token)) => { output.send(Msg::Token(Bytes::copy_from_slice(&*token))).expect("send"); client = ctx; } } }; let msg = client.wrap(true, b"super secret message").expect("wrap"); output.send(Msg::Msg(Bytes::copy_from_slice(&*msg))).expect("send"); } fn main() { let args = args().collect::>(); if args.len() != 2 { println!("usage: {}: ", args[0]); exit(1); } let spn = String::from(&args[1]); let (server_snd, server_recv) = mpsc::channel(); let (client_snd, client_recv) = mpsc::channel(); thread::spawn(move || server(spn, server_recv, client_snd)); client(&args[1], client_recv, server_snd); } ``` -------------------------------- ### High-Performance Scatter/Gather I/O with K5Ctx::wrap_iov Source: https://context7.com/estokes/cross-krb5/llms.txt Utilize wrap_iov and unwrap_iov for high-performance, in-place encryption/decryption of data, ideal for scatter/gather I/O operations. These methods are significantly faster on supported platforms and avoid data copying. ```rust use bytes::BytesMut; use cross_krb5::{ClientCtx, InitiateFlags, K5Ctx, Step}; fn high_performance_encryption(ctx: &mut impl K5Ctx) -> anyhow::Result<()> { // Prepare message data in a BytesMut buffer let mut message = BytesMut::from(&b"Large payload data for high-throughput scenario..."[..]); // wrap_iov encrypts in-place and returns a chained buffer ready for writev let encrypted_chain = ctx.wrap_iov(true, message)?; // Use with tokio's write_buf or extract iovecs for writev syscall // The buffer is non-contiguous but can be sent efficiently use bytes::Buf; let total_len = encrypted_chain.remaining(); println!("Encrypted IOV buffer total size: {} bytes", total_len); // For receiving: unwrap_iov decrypts in-place let mut received_buffer = BytesMut::from(&encrypted_data[..]); let message_len = received_buffer.len(); let decrypted = ctx.unwrap_iov(message_len, &mut received_buffer)?; println!("Decrypted: {}", String::from_utf8_lossy(&decrypted)); Ok(()) } ``` -------------------------------- ### K5Ctx::wrap_iov and K5Ctx::unwrap_iov Source: https://context7.com/estokes/cross-krb5/llms.txt High-performance scatter/gather I/O methods that encrypt/decrypt data in-place without copying. Ideal for high-throughput applications. ```APIDOC ## K5Ctx::wrap_iov and K5Ctx::unwrap_iov ### Description High-performance scatter/gather I/O methods that encrypt/decrypt data in-place without copying. These are 2-3x faster than regular wrap/unwrap on platforms that support IOV operations (Linux, Windows). Ideal for high-throughput applications. ### Method `wrap_iov`: POST (conceptual) `unwrap_iov`: POST (conceptual) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **encrypt** (boolean) - Required - Whether to encrypt the data. - **buffer** (BytesMut) - Required - The buffer containing the data to be encrypted/decrypted in-place. - **message_len** (usize) - Required for unwrap_iov - The length of the message to unwrap. ### Request Example ```json { "encrypt": true, "buffer": "Large payload data for high-throughput scenario..." } ``` ### Response #### Success Response (200) - **encrypted_chain** (BytesMut) - A chained buffer ready for scatter/gather operations (for wrap_iov). - **decrypted_data** (bytes) - The decrypted message (for unwrap_iov). #### Response Example ```json { "encrypted_chain": "chained_buffer_representation" } ``` ```json { "decrypted_data": "Decrypted: Large payload data..." } ``` ``` -------------------------------- ### Manage Kerberos Credentials with Cred and K5Cred Source: https://context7.com/estokes/cross-krb5/llms.txt Acquire and manage Kerberos credentials for server and client contexts. Supports interoperability with platform-native credential types on Unix. ```rust use cross_krb5::{Cred, K5Cred, AcceptFlags, InitiateFlags, ServerCtx, ClientCtx}; fn credential_management() -> anyhow::Result<()> { // Acquire server credentials explicitly let server_cred = Cred::server_acquire( AcceptFlags::empty(), Some("HTTP/myserver.example.com@EXAMPLE.COM"), )?; // Create server context with pre-acquired credentials let pending_server = ServerCtx::new_with_cred(server_cred)?; // Acquire client credentials for a specific principal let client_cred = Cred::client_acquire( InitiateFlags::empty(), Some("user@EXAMPLE.COM"), )?; // Create client context with pre-acquired credentials let (pending_client, token) = ClientCtx::new_with_cred( client_cred, "HTTP/server.example.com@EXAMPLE.COM", None, )?; Ok(()) } // Unix-only: Convert from/to libgssapi credentials #[cfg(unix)] fn gssapi_interop() -> anyhow::Result<()> { use libgssapi::credential::{Cred as GssCred, CredUsage}; // Acquire via libgssapi let gss_cred = GssCred::acquire(None, None, CredUsage::Accept, None)?; // Convert to cross-krb5 Cred let cred: Cred = Cred::from(gss_cred); // Convert back to libgssapi Cred let gss_cred_back: GssCred = cred.into(); Ok(()) } ``` -------------------------------- ### Encrypt and Sign Messages with K5Ctx::wrap Source: https://context7.com/estokes/cross-krb5/llms.txt Use wrap to encrypt and/or sign messages for secure transmission. Even without encryption, it protects message integrity. Ensure a secure context is established before use. ```rust use cross_krb5::{ClientCtx, InitiateFlags, K5Ctx, Step}; fn secure_message_exchange(target_spn: &str) -> anyhow::Result<()> { // Establish authenticated context (simplified) let (pending, token) = ClientCtx::new(InitiateFlags::empty(), None, target_spn, None)?; let server_response = exchange_with_server(&token)?; let mut ctx = match pending.step(&server_response)? { Step::Finished((ctx, _)) => ctx, Step::Continue(_) => panic!("Expected single-step auth"), }; // Encrypt a confidential message (encrypt = true) let secret_message = b"Sensitive data: account balance $1,000,000"; let encrypted = ctx.wrap(true, secret_message)?; println!("Original: {} bytes, Encrypted: {} bytes", secret_message.len(), encrypted.len()); // Sign-only mode (encrypt = false) - integrity protected but readable let public_message = b"This message is signed but not encrypted"; let signed = ctx.wrap(false, public_message)?; // Decrypt/verify received message let incoming_encrypted = receive_encrypted_message()?; let decrypted = ctx.unwrap(&incoming_encrypted)?; println!("Decrypted message: {}", String::from_utf8_lossy(&decrypted)); Ok(()) } ``` -------------------------------- ### K5ServerCtx::client Source: https://context7.com/estokes/cross-krb5/llms.txt Retrieves the authenticated client's principal name from a server context. Use this for authorization decisions, audit logging, and identifying the connected user. ```APIDOC ## K5ServerCtx::client ### Description Retrieves the authenticated client's principal name from a server context. Use this for authorization decisions, audit logging, and identifying the connected user. ### Method `client`: GET (conceptual) ### Parameters None ### Request Example None (This is a method call on an existing server context) ### Response #### Success Response (200) - **client_principal** (string) - The Kerberos principal name of the authenticated client. #### Response Example ```json { "client_principal": "user@REALM.COM" } ``` ``` -------------------------------- ### Check Security Context Time-to-Live with K5Ctx::ttl Source: https://context7.com/estokes/cross-krb5/llms.txt Use the ttl method to retrieve the remaining time-to-live for a security context. This is crucial for monitoring session validity and implementing timely credential refresh before expiration. ```rust use cross_krb5::{ClientCtx, InitiateFlags, K5Ctx, Step}; use std::time::Duration; fn check_session_validity(ctx: &mut impl K5Ctx) -> anyhow::Result<()> { let remaining = ctx.ttl()?; if remaining < Duration::from_secs(300) { println!("Warning: Session expires in {} seconds, consider re-authenticating", remaining.as_secs()); } else { println!("Session valid for {} more minutes", remaining.as_secs() / 60); } // Implement automatic refresh logic if remaining < Duration::from_secs(60) { return Err(anyhow::anyhow!("Session expired, re-authentication required")); } Ok(()) } ``` -------------------------------- ### K5Ctx::ttl Source: https://context7.com/estokes/cross-krb5/llms.txt Returns the remaining time-to-live for the security context. Use this to check session validity and implement credential refresh before expiration. ```APIDOC ## K5Ctx::ttl ### Description Returns the remaining time-to-live for the security context. Use this to check session validity and implement credential refresh before expiration. ### Method `ttl`: GET (conceptual) ### Parameters None ### Request Example None (This is a method call on an existing context) ### Response #### Success Response (200) - **remaining_ttl** (Duration) - The remaining time-to-live for the security context. #### Response Example ```json { "remaining_ttl": "300s" } ``` ``` -------------------------------- ### Retrieve Client Principal with K5ServerCtx::client Source: https://context7.com/estokes/cross-krb5/llms.txt The K5ServerCtx::client method retrieves the authenticated client's principal name. This is essential for authorization decisions, audit logging, and identifying the connected user. ```rust use cross_krb5::{ServerCtx, AcceptFlags, Step, K5ServerCtx}; fn authorize_client(server_ctx: &mut impl K5ServerCtx) -> anyhow::Result { // Get the authenticated client's Kerberos principal let client_principal = server_ctx.client()?; println!("Client authenticated as: {}", client_principal); // Example: Parse principal for authorization (format: user@REALM) let allowed_users = vec!["admin@EXAMPLE.COM", "service-account@EXAMPLE.COM"]; if allowed_users.contains(&client_principal.as_str()) { println!("Access granted to {}", client_principal); Ok(true) } else { println!("Access denied for {}", client_principal); Ok(false) } } ``` -------------------------------- ### K5Ctx::wrap and K5Ctx::unwrap Source: https://context7.com/estokes/cross-krb5/llms.txt Encrypts, decrypts, and signs messages for secure transmission. Wrap protects message integrity even without encryption. ```APIDOC ## K5Ctx::wrap and K5Ctx::unwrap ### Description Encrypts and/or signs a message for secure transmission, while unwrap decrypts and verifies incoming messages. Even without encryption, wrap protects message integrity so tampering can be detected. ### Method `wrap`: POST (conceptual, as it's a method call) `unwrap`: POST (conceptual, as it's a method call) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **encrypt** (boolean) - Required - Whether to encrypt the message. - **message** (bytes) - Required - The message payload to wrap or unwrap. ### Request Example ```json { "encrypt": true, "message": "Sensitive data: account balance $1,000,000" } ``` ### Response #### Success Response (200) - **wrapped_data** (bytes) - The encrypted and/or signed message. - **decrypted_data** (bytes) - The decrypted and verified message. #### Response Example ```json { "wrapped_data": "base64_encoded_encrypted_data" } ``` ```json { "decrypted_data": "Sensitive data: account balance $1,000,000" } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.