1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-15 19:06:03 +00:00

Merge pull request #6450 from mailcow/fix/sasl_logs

Fix sasl_logs
This commit is contained in:
FreddleSpl0it
2025-04-03 12:38:13 +02:00
committed by GitHub
7 changed files with 81 additions and 43 deletions

View File

@@ -69,29 +69,34 @@ require_once 'functions.acl.inc.php';
$isSOGoRequest = $post['real_rip'] == getenv('IPV4_NETWORK') . '.248'; $isSOGoRequest = $post['real_rip'] == getenv('IPV4_NETWORK') . '.248';
$result = false; $result = false;
$protocol = $post['protocol'];
if ($isSOGoRequest) { if ($isSOGoRequest) {
$protocol = null;
// This is a SOGo Auth request. First check for SSO password. // This is a SOGo Auth request. First check for SSO password.
$sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass"); $sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass");
if ($sogo_sso_pass === $post['password']){ if ($sogo_sso_pass === $post['password']){
error_log('MAILCOWAUTH: SOGo SSO auth for user ' . $post['username']); error_log('MAILCOWAUTH: SOGo SSO auth for user ' . $post['username']);
set_sasl_log($post['username'], $post['real_rip'], "SOGO");
$result = true; $result = true;
} }
} }
if ($result === false){ if ($result === false){
$result = apppass_login($post['username'], $post['password'], $protocol, array( $result = apppass_login($post['username'], $post['password'], array($post['service'] => true), array(
'is_internal' => true, 'is_internal' => true,
'remote_addr' => $post['real_rip'] 'remote_addr' => $post['real_rip']
)); ));
if ($result) error_log('MAILCOWAUTH: App auth for user ' . $post['username']); if ($result) {
error_log('MAILCOWAUTH: App auth for user ' . $post['username']);
set_sasl_log($post['username'], $post['real_rip'], $post['service']);
}
} }
if ($result === false){ if ($result === false){
// Init Identity Provider // Init Identity Provider
$iam_provider = identity_provider('init'); $iam_provider = identity_provider('init');
$iam_settings = identity_provider('get'); $iam_settings = identity_provider('get');
$result = user_login($post['username'], $post['password'], array('is_internal' => true)); $result = user_login($post['username'], $post['password'], array('is_internal' => true));
if ($result) error_log('MAILCOWAUTH: User auth for user ' . $post['username']); if ($result) {
error_log('MAILCOWAUTH: User auth for user ' . $post['username']);
set_sasl_log($post['username'], $post['real_rip'], $post['service']);
}
} }
if ($result) { if ($result) {

View File

@@ -12,12 +12,11 @@ function auth_password_verify(request, password)
username = request.user, username = request.user,
password = password, password = password,
real_rip = request.real_rip, real_rip = request.real_rip,
protocol = {} service = request.service
} }
req.protocol[request.service] = true
local req_json = json.encode(req) local req_json = json.encode(req)
local res = {} local res = {}
local b, c = https.request { local b, c = https.request {
method = "POST", method = "POST",
url = "https://nginx:9082", url = "https://nginx:9082",
@@ -33,7 +32,7 @@ function auth_password_verify(request, password)
if api_response.success == true then if api_response.success == true then
return dovecot.auth.PASSDB_RESULT_OK, "" return dovecot.auth.PASSDB_RESULT_OK, ""
end end
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate" return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
end end

View File

@@ -53,7 +53,7 @@ mail_shared_explicit_inbox = yes
mail_prefetch_count = 30 mail_prefetch_count = 30
passdb { passdb {
driver = lua driver = lua
args = file=/etc/dovecot/auth/passwd-verify.lua blocking=yes cache_key=%u:%w args = file=/etc/dovecot/auth/passwd-verify.lua blocking=yes cache_key=%s:%u:%w
result_success = return-ok result_success = return-ok
result_failure = continue result_failure = continue
result_internalfail = continue result_internalfail = continue

View File

@@ -9,25 +9,52 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
// Try validate admin // Try validate admin
if (!isset($role) || $role == "admin") { if (!isset($role) || $role == "admin") {
$result = admin_login($user, $pass); $result = admin_login($user, $pass);
if ($result !== false) return $result; if ($result !== false){
return $result;
}
} }
// Try validate domain admin // Try validate domain admin
if (!isset($role) || $role == "domain_admin") { if (!isset($role) || $role == "domain_admin") {
$result = domainadmin_login($user, $pass); $result = domainadmin_login($user, $pass);
if ($result !== false) return $result; if ($result !== false) {
return $result;
}
}
// Try validate app password
if (!isset($role) || $role == "app") {
$result = apppass_login($user, $pass, $app_passwd_data);
if ($result !== false) {
if ($app_passwd_data['eas'] === true) {
$service = 'EAS';
} elseif ($app_passwd_data['dav'] === true) {
$service = 'DAV';
} else {
$service = 'NONE';
}
$real_rip = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']);
set_sasl_log($user, $real_rip, $service, $pass);
return $result;
}
} }
// Try validate user // Try validate user
if (!isset($role) || $role == "user") { if (!isset($role) || $role == "user") {
$result = user_login($user, $pass); $result = user_login($user, $pass);
if ($result !== false) return $result; if ($result !== false) {
} if ($app_passwd_data['eas'] === true) {
$service = 'EAS';
// Try validate app password } elseif ($app_passwd_data['dav'] === true) {
if (!isset($role) || $role == "app") { $service = 'DAV';
$result = apppass_login($user, $pass, $app_passwd_data); } else {
if ($result !== false) return $result; $service = 'MAILCOWUI';
}
$real_rip = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']);
set_sasl_log($user, $real_rip, $service);
return $result;
}
} }
// skip log and only return false if it's an internal request // skip log and only return false if it's an internal request
@@ -415,21 +442,7 @@ function apppass_login($user, $pass, $app_passwd_data, $extra = null){
// verify password // verify password
if (verify_hash($row['password'], $pass) !== false) { if (verify_hash($row['password'], $pass) !== false) {
if ($is_internal){ $_SESSION['app_passwd_id'] = $row['app_passwd_id'];
$remote_addr = $extra['remote_addr'];
} else {
$remote_addr = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']);
}
$service = strtoupper($is_app_passwd);
$stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)");
$stmt->execute(array(
':service' => $service,
':app_id' => $row['app_passwd_id'],
':username' => $user,
':remote_addr' => $remote_addr
));
unset($_SESSION['ldelay']); unset($_SESSION['ldelay']);
return "user"; return "user";
} }

View File

@@ -350,6 +350,34 @@ function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
} }
} }
function set_sasl_log($username, $real_rip, $service){
global $pdo;
try {
if (!empty($_SESSION['app_passwd_id'])) {
$app_password = $_SESSION['app_passwd_id'];
} else {
$app_password = 0;
}
$stmt = $pdo->prepare('REPLACE INTO `sasl_log` (`username`, `real_rip`, `service`, `app_password`) VALUES (:username, :real_rip, :service, :app_password)');
$stmt->execute(array(
':username' => $username,
':real_rip' => $real_rip,
':service' => $service,
':app_password' => $app_password
));
} catch (PDOException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => array('mysql_error', $e)
);
return false;
}
return true;
}
function flush_memcached() { function flush_memcached() {
try { try {
$m = new Memcached(); $m = new Memcached();

View File

@@ -90,13 +90,7 @@ jQuery(function($){
console.log('error reading last logins'); console.log('error reading last logins');
}, },
success: function (data) { success: function (data) {
$('.last-ui-login').html('');
$('.last-sasl-login').html(''); $('.last-sasl-login').html('');
if (data.ui.time) {
$('.last-ui-login').html('<i class="bi bi-person-fill"></i> ' + lang.last_ui_login + ': ' + unix_time_format(data.ui.time));
} else {
$('.last-ui-login').text(lang.no_last_login);
}
if (data.sasl) { if (data.sasl) {
$('.last-sasl-login').append('<ul class="list-group">'); $('.last-sasl-login').append('<ul class="list-group">');
$.each(data.sasl, function (i, item) { $.each(data.sasl, function (i, item) {

View File

@@ -184,7 +184,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="ms-auto col-xl-3 col-lg-5 col-md-12 col-12 d-flex flex-column well flex-grow-1"> <div class="ms-auto col-xl-3 col-lg-5 col-md-12 col-12 d-flex flex-column well flex-grow-1" id="recent-logins">
<legend class="d-flex"> <legend class="d-flex">
<span>{{ lang.user.recent_successful_connections }}</span> <span>{{ lang.user.recent_successful_connections }}</span>
<div id="spinner-last-login" class="ms-auto my-auto spinner-border spinner-border-sm d-none" role="status"> <div id="spinner-last-login" class="ms-auto my-auto spinner-border spinner-border-sm d-none" role="status">
@@ -192,7 +192,6 @@
</div> </div>
</legend> </legend>
<hr> <hr>
<h6 class="last-ui-login"></h6>
<div class="d-flex"> <div class="d-flex">
<span class="clear-last-logins mt-auto mb-2"> <span class="clear-last-logins mt-auto mb-2">
{{ lang.user.clear_recent_successful_connections }} {{ lang.user.clear_recent_successful_connections }}