fixed #855 - log client IPs and credentials used

This commit is contained in:
Eugene Pankov 2023-08-08 09:39:22 +02:00 committed by Eugene
parent 0c7ed120b9
commit 49b92cde7a
7 changed files with 49 additions and 18 deletions

View file

@ -43,4 +43,14 @@ impl AuthCredential {
Self::WebUserApproval => CredentialKind::WebUserApproval,
}
}
pub fn safe_description(&self) -> String {
match self {
Self::Password { .. } => "password".to_string(),
Self::PublicKey { .. } => "public key".to_string(),
Self::Otp { .. } => "one-time password".to_string(),
Self::Sso { provider, .. } => format!("SSO ({provider})"),
Self::WebUserApproval => "in-browser auth".to_string(),
}
}
}

View file

@ -2,6 +2,7 @@ use std::collections::HashSet;
use chrono::{DateTime, Utc};
use rand::Rng;
use tracing::info;
use uuid::Uuid;
use super::{AuthCredential, CredentialKind, CredentialPolicy, CredentialPolicyResponse};
@ -96,9 +97,20 @@ impl AuthState {
.policy
.is_sufficient(&self.protocol, &self.valid_credentials[..])
{
CredentialPolicyResponse::Ok => AuthResult::Accepted {
username: self.username.clone(),
},
CredentialPolicyResponse::Ok => {
info!(
username=%self.username,
credentials=%self.valid_credentials
.iter()
.map(|x| x.safe_description())
.collect::<Vec<_>>()
.join(", "),
"Authenticated",
);
AuthResult::Accepted {
username: self.username.clone(),
}
}
CredentialPolicyResponse::Need(kinds) => AuthResult::Need(kinds),
}
}

View file

@ -222,7 +222,6 @@ pub async fn authorize_session(req: &Request, username: String) -> poem::Result<
.await
.set_username(username.clone())
.await?;
info!(%username, "Authenticated");
session.set_auth(SessionAuthorization::User(username));
Ok(())

View file

@ -7,15 +7,21 @@ use crate::session_handle::WarpgateServerHandleFromRequest;
pub async fn span_for_request(req: &Request) -> poem::Result<Span> {
let handle = WarpgateServerHandleFromRequest::from_request_without_body(req).await;
let client_ip = req
.remote_addr()
.as_socket_addr()
.map(|x| x.ip().to_string())
.unwrap_or("<unknown>".into());
Ok(match handle {
Ok(ref handle) => {
let handle = handle.lock().await;
let ss = handle.session_state().lock().await;
match { ss.username.clone() } {
Some(ref username) => {
info_span!("HTTP", session=%handle.id(), session_username=%username)
info_span!("HTTP", session=%handle.id(), session_username=%username, %client_ip)
}
None => info_span!("HTTP", session=%handle.id()),
None => info_span!("HTTP", session=%handle.id(), %client_ip),
}
}
Err(_) => info_span!("HTTP"),

View file

@ -86,13 +86,13 @@ impl ProtocolServer for MySQLProtocolServer {
.register_session(
&crate::common::PROTOCOL_NAME,
SessionStateInit {
remote_address: Some(remote_address),
remote_address: Some(remote_address.clone()),
handle: Box::new(session_handle),
},
)
.await?;
let session = MySqlSession::new(server_handle, services, stream, tls_config).await;
let session = MySqlSession::new(server_handle, services, stream, tls_config, remote_address).await;
let span = session.make_logging_span();
tokio::select! {
result = session.run().instrument(span) => match result {

View file

@ -1,3 +1,4 @@
use std::net::SocketAddr;
use std::sync::Arc;
use bytes::{Buf, Bytes, BytesMut};
@ -34,6 +35,7 @@ pub struct MySqlSession {
server_handle: Arc<Mutex<WarpgateServerHandle>>,
id: Uuid,
services: Services,
remote_address: SocketAddr,
}
impl MySqlSession {
@ -42,6 +44,7 @@ impl MySqlSession {
services: Services,
stream: TcpStream,
tls_config: ServerConfig,
remote_address: SocketAddr,
) -> Self {
let id = server_handle.lock().await.id();
Self {
@ -67,13 +70,17 @@ impl MySqlSession {
database: None,
server_handle,
id,
remote_address,
}
}
pub fn make_logging_span(&self) -> tracing::Span {
let client_ip = self.remote_address.ip().to_string();
match self.username {
Some(ref username) => info_span!("MySQL", session=%self.id, session_username=%username),
None => info_span!("MySQL", session=%self.id),
Some(ref username) => {
info_span!("MySQL", session=%self.id, session_username=%username, %client_ip)
}
None => info_span!("MySQL", session=%self.id, %client_ip),
}
}
@ -269,8 +276,6 @@ impl MySqlSession {
)?;
self.stream.flush().await?;
info!(%username, "Authenticated");
let target = {
self.services
.config_provider
@ -307,9 +312,7 @@ impl MySqlSession {
handle.set_target(&target).await?;
}
let span = self.make_logging_span();
self.run_authorized_inner(handshake, mysql_options)
.instrument(span)
.await
}

View file

@ -238,9 +238,12 @@ impl ServerSession {
}
pub fn make_logging_span(&self) -> tracing::Span {
let client_ip = self.remote_address.ip().to_string();
match self.username {
Some(ref username) => info_span!("SSH", session=%self.id, session_username=%username),
None => info_span!("SSH", session=%self.id),
Some(ref username) => {
info_span!("SSH", session=%self.id, session_username=%username, %client_ip)
}
None => info_span!("SSH", session=%self.id, %client_ip),
}
}
@ -1437,8 +1440,6 @@ impl ServerSession {
username: &str,
target_name: &str,
) -> Result<(), WarpgateError> {
info!(%username, "Authenticated");
let _ = self
.server_handle
.lock()