1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-13 09:56:01 +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';
$result = false;
$protocol = $post['protocol'];
if ($isSOGoRequest) {
$protocol = null;
// This is a SOGo Auth request. First check for SSO password.
$sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass");
if ($sogo_sso_pass === $post['password']){
error_log('MAILCOWAUTH: SOGo SSO auth for user ' . $post['username']);
set_sasl_log($post['username'], $post['real_rip'], "SOGO");
$result = true;
}
}
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,
'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){
// Init Identity Provider
$iam_provider = identity_provider('init');
$iam_settings = identity_provider('get');
$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) {

View File

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

View File

@@ -53,7 +53,7 @@ mail_shared_explicit_inbox = yes
mail_prefetch_count = 30
passdb {
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_failure = continue
result_internalfail = continue

View File

@@ -9,25 +9,52 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
// Try validate admin
if (!isset($role) || $role == "admin") {
$result = admin_login($user, $pass);
if ($result !== false) return $result;
if ($result !== false){
return $result;
}
}
// Try validate domain admin
if (!isset($role) || $role == "domain_admin") {
$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
if (!isset($role) || $role == "user") {
$result = user_login($user, $pass);
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) return $result;
if ($result !== false) {
if ($app_passwd_data['eas'] === true) {
$service = 'EAS';
} elseif ($app_passwd_data['dav'] === true) {
$service = 'DAV';
} else {
$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
@@ -415,21 +442,7 @@ function apppass_login($user, $pass, $app_passwd_data, $extra = null){
// verify password
if (verify_hash($row['password'], $pass) !== false) {
if ($is_internal){
$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
));
$_SESSION['app_passwd_id'] = $row['app_passwd_id'];
unset($_SESSION['ldelay']);
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() {
try {
$m = new Memcached();

View File

@@ -90,13 +90,7 @@ jQuery(function($){
console.log('error reading last logins');
},
success: function (data) {
$('.last-ui-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) {
$('.last-sasl-login').append('<ul class="list-group">');
$.each(data.sasl, function (i, item) {

View File

@@ -184,7 +184,7 @@
</div>
{% endif %}
</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">
<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">
@@ -192,7 +192,6 @@
</div>
</legend>
<hr>
<h6 class="last-ui-login"></h6>
<div class="d-flex">
<span class="clear-last-logins mt-auto mb-2">
{{ lang.user.clear_recent_successful_connections }}