You've already forked mailcow-dockerized
mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2025-07-07 01:06:59 +02:00
[Web] organize auth functions+api auth w/ dovecot
This commit is contained in:
committed by
DerLinkman
parent
50d4d59626
commit
6adad79e5c
@ -26,6 +26,7 @@ RUN addgroup -g 5000 vmail \
|
|||||||
curl \
|
curl \
|
||||||
jq \
|
jq \
|
||||||
lua \
|
lua \
|
||||||
|
lua-json \
|
||||||
lua-cjson \
|
lua-cjson \
|
||||||
lua-socket \
|
lua-socket \
|
||||||
lua-sql-mysql \
|
lua-sql-mysql \
|
||||||
|
@ -129,114 +129,86 @@ iterate_query = SELECT username FROM mailbox WHERE active = '1' OR active = '2';
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /etc/dovecot/lua/passwd-verify.lua
|
cat <<EOF > /etc/dovecot/lua/passwd-verify.lua
|
||||||
function auth_password_verify(req, pass)
|
function auth_password_verify(request, password)
|
||||||
|
if request.domain == nil then
|
||||||
if req.domain == nil then
|
|
||||||
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "No such user"
|
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "No such user"
|
||||||
end
|
end
|
||||||
|
|
||||||
if cur == nil then
|
json = require "json"
|
||||||
script_init()
|
ltn12 = require "ltn12"
|
||||||
end
|
http = require "socket.http"
|
||||||
|
http.TIMEOUT = 5
|
||||||
if req.user == nil then
|
mysql = require "luasql.mysql"
|
||||||
req.user = ''
|
env = mysql.mysql()
|
||||||
end
|
con = env:connect("__DBNAME__","__DBUSER__","__DBPASS__","localhost")
|
||||||
|
|
||||||
respbody = {}
|
|
||||||
|
|
||||||
|
local req = {
|
||||||
|
username = request.user,
|
||||||
|
password = password
|
||||||
|
}
|
||||||
|
local req_json = json.encode(req)
|
||||||
|
local res = {}
|
||||||
|
|
||||||
-- check against mailbox passwds
|
-- check against mailbox passwds
|
||||||
local cur,errorString = con:execute(string.format([[SELECT password FROM mailbox
|
local b, c = http.request {
|
||||||
WHERE username = '%s'
|
method = "POST",
|
||||||
AND active = '1'
|
url = "https://nginx/api/v1/process/login",
|
||||||
AND domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')
|
source = ltn12.source.string(req_json),
|
||||||
AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.force_pw_update')), 0) != '1'
|
headers = {
|
||||||
AND IFNULL(JSON_UNQUOTE(JSON_VALUE(attributes, '$.%s_access')), 1) = '1']], con:escape(req.user), con:escape(req.domain), con:escape(req.service)))
|
["content-type"] = "application/json",
|
||||||
local row = cur:fetch ({}, "a")
|
["content-length"] = tostring(#req_json)
|
||||||
while row do
|
},
|
||||||
if req.password_verify(req, row.password, pass) == 1 then
|
sink = ltn12.sink.table(res)
|
||||||
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
|
}
|
||||||
VALUES ("%s", 0, "%s", "%s")]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip)))
|
local api_response = json.decode(table.concat(res))
|
||||||
cur:close()
|
if api_response.role == 'user' then
|
||||||
con:close()
|
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
|
||||||
return dovecot.auth.PASSDB_RESULT_OK, ""
|
VALUES ("%s", 0, "%s", "%s")]], con:escape(request.service), con:escape(request.user), con:escape(request.real_rip)))
|
||||||
end
|
con:close()
|
||||||
row = cur:fetch (row, "a")
|
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. password
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- check against app passwds for imap and smtp
|
-- check against app passwds for imap and smtp
|
||||||
-- app passwords are only available for imap, smtp, sieve and pop3 when using sasl
|
-- app passwords are only available for imap, smtp, sieve and pop3 when using sasl
|
||||||
if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then
|
if request.service == "smtp" or request.service == "imap" or request.service == "sieve" or request.service == "pop3" then
|
||||||
local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, %s_access AS has_prot_access, app_passwd.password FROM app_passwd
|
req.protocol = {}
|
||||||
INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox
|
req.protocol[request.service] = true
|
||||||
WHERE mailbox = '%s'
|
req_json = json.encode(req)
|
||||||
AND app_passwd.active = '1'
|
|
||||||
AND mailbox.active = '1'
|
req.protocol.ignore_hasaccess = false
|
||||||
AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.service), con:escape(req.user), con:escape(req.domain)))
|
if tostring(req.real_rip) == "__IPV4_SOGO__" then
|
||||||
local row = cur:fetch ({}, "a")
|
req.protocol.ignore_hasaccess = true
|
||||||
while row do
|
end
|
||||||
if req.password_verify(req, row.password, pass) == 1 then
|
|
||||||
-- if password is valid and protocol access is 1 OR real_rip matches SOGo, proceed
|
local b, c = http.request {
|
||||||
if tostring(req.real_rip) == "__IPV4_SOGO__" then
|
method = "POST",
|
||||||
cur:close()
|
url = "https://nginx/api/v1/process/login",
|
||||||
con:close()
|
source = ltn12.source.string(req_json),
|
||||||
return dovecot.auth.PASSDB_RESULT_OK, ""
|
headers = {
|
||||||
elseif row.has_prot_access == "1" then
|
["content-type"] = "application/json",
|
||||||
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
|
["content-length"] = tostring(#req_json)
|
||||||
VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
|
},
|
||||||
cur:close()
|
sink = ltn12.sink.table(res)
|
||||||
con:close()
|
}
|
||||||
return dovecot.auth.PASSDB_RESULT_OK, ""
|
local api_response = json.decode(table.concat(res))
|
||||||
end
|
if api_response.role == 'user' then
|
||||||
|
if req.protocol.ignore_hasaccess == false then
|
||||||
|
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
|
||||||
|
VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
|
||||||
end
|
end
|
||||||
row = cur:fetch (row, "a")
|
con:close()
|
||||||
|
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. password
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cur:close()
|
|
||||||
con:close()
|
con:close()
|
||||||
|
|
||||||
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
|
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
|
||||||
|
|
||||||
-- PoC
|
|
||||||
-- local reqbody = string.format([[{
|
|
||||||
-- "success":0,
|
|
||||||
-- "service":"%s",
|
|
||||||
-- "app_password":false,
|
|
||||||
-- "username":"%s",
|
|
||||||
-- "real_rip":"%s"
|
|
||||||
-- }]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip))
|
|
||||||
-- http.request {
|
|
||||||
-- method = "POST",
|
|
||||||
-- url = "http://nginx:8081/sasl_log.php",
|
|
||||||
-- source = ltn12.source.string(reqbody),
|
|
||||||
-- headers = {
|
|
||||||
-- ["content-type"] = "application/json",
|
|
||||||
-- ["content-length"] = tostring(#reqbody)
|
|
||||||
-- },
|
|
||||||
-- sink = ltn12.sink.table(respbody)
|
|
||||||
-- }
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function auth_passdb_lookup(req)
|
function auth_passdb_lookup(req)
|
||||||
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, ""
|
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, ""
|
||||||
end
|
end
|
||||||
|
|
||||||
function script_init()
|
|
||||||
mysql = require "luasql.mysql"
|
|
||||||
http = require "socket.http"
|
|
||||||
http.TIMEOUT = 5
|
|
||||||
ltn12 = require "ltn12"
|
|
||||||
env = mysql.mysql()
|
|
||||||
con = env:connect("__DBNAME__","__DBUSER__","__DBPASS__","localhost")
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function script_deinit()
|
|
||||||
con:close()
|
|
||||||
env:close()
|
|
||||||
end
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Replace patterns in app-passdb.lua
|
# Replace patterns in app-passdb.lua
|
||||||
|
278
data/web/inc/functions.auth.inc.php
Normal file
278
data/web/inc/functions.auth.inc.php
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
<?php
|
||||||
|
function check_login($user, $pass, $app_passwd_data = false) {
|
||||||
|
global $pdo;
|
||||||
|
global $redis;
|
||||||
|
|
||||||
|
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => 'malformed_username'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate admin
|
||||||
|
$result = mailcow_admin_login($user, $pass);
|
||||||
|
if ($result){
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate domain admin
|
||||||
|
$result = mailcow_domainadmin_login($user, $pass);
|
||||||
|
if ($result){
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate mailbox user
|
||||||
|
// skip log & ldelay if requests comes from dovecot
|
||||||
|
$is_dovecot = false;
|
||||||
|
$request_ip = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']);
|
||||||
|
if ($request_ip == getenv('IPV4_NETWORK').'.250'){
|
||||||
|
$is_dovecot = true;
|
||||||
|
}
|
||||||
|
// check authsource
|
||||||
|
$stmt = $pdo->prepare("SELECT authsource FROM `mailbox`
|
||||||
|
INNER JOIN domain on mailbox.domain = domain.domain
|
||||||
|
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||||
|
AND `mailbox`.`active`='1'
|
||||||
|
AND `domain`.`active`='1'
|
||||||
|
AND `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if ($row['authsource'] == 'keycloak'){
|
||||||
|
$result = keycloak_mbox_login($user, $pass, $is_dovecot);
|
||||||
|
if ($result){
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = mailcow_mbox_login($user, $pass, $app_passwd_data, $is_dovecot);
|
||||||
|
if ($result){
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip log and only return false
|
||||||
|
// netfilter uses dovecot error log for banning
|
||||||
|
if ($is_dovecot){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isset($_SESSION['ldelay'])) {
|
||||||
|
$_SESSION['ldelay'] = "0";
|
||||||
|
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
|
}
|
||||||
|
elseif (!isset($_SESSION['mailcow_cc_username'])) {
|
||||||
|
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
|
||||||
|
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => 'login_failed'
|
||||||
|
);
|
||||||
|
|
||||||
|
sleep($_SESSION['ldelay']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mailcow_mbox_login($user, $pass, $app_passwd_data = false, $is_internal = false){
|
||||||
|
global $pdo;
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `mailbox`
|
||||||
|
INNER JOIN domain on mailbox.domain = domain.domain
|
||||||
|
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||||
|
AND `mailbox`.`active`='1'
|
||||||
|
AND `domain`.`active`='1'
|
||||||
|
AND (`mailbox`.`authsource`='mailcow' OR `mailbox`.`authsource` IS NULL)
|
||||||
|
AND `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// check if password is app password
|
||||||
|
$is_app_passwd = false;
|
||||||
|
if ($app_passwd_data['eas']){
|
||||||
|
$is_app_passwd = 'eas';
|
||||||
|
} else if ($app_passwd_data['dav']){
|
||||||
|
$is_app_passwd = 'dav';
|
||||||
|
} else if ($app_passwd_data['smtp']){
|
||||||
|
$is_app_passwd = 'smtp';
|
||||||
|
} else if ($app_passwd_data['imap']){
|
||||||
|
$is_app_passwd = 'imap';
|
||||||
|
} else if ($app_passwd_data['sieve']){
|
||||||
|
$is_app_passwd = 'sieve';
|
||||||
|
} else if ($app_passwd_data['pop3']){
|
||||||
|
$is_app_passwd = 'pop3';
|
||||||
|
}
|
||||||
|
if ($is_app_passwd){
|
||||||
|
// fetch app password data
|
||||||
|
$app_passwd_query = "SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd`
|
||||||
|
INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox`
|
||||||
|
INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
|
||||||
|
WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group'
|
||||||
|
AND `mailbox`.`active` = '1'
|
||||||
|
AND `domain`.`active` = '1'
|
||||||
|
AND `app_passwd`.`active` = '1'
|
||||||
|
AND `app_passwd`.`mailbox` = :user";
|
||||||
|
// check if app password has protocol access
|
||||||
|
// skip if $app_passwd_data['ignore_hasaccess'] is true and the call is not external
|
||||||
|
if (!$app_passwd_data['ignore_hasaccess'] || !$is_internal){
|
||||||
|
$app_passwd_query = $app_passwd_query . " AND `app_passwd`.`" . $is_app_passwd . "_access` = '1'";
|
||||||
|
}
|
||||||
|
// fetch password data
|
||||||
|
$stmt = $pdo->prepare($app_passwd_query);
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
// verify password
|
||||||
|
if (verify_hash($row['password'], $pass) !== false) {
|
||||||
|
if (!$is_app_passwd){
|
||||||
|
// password is not a app password
|
||||||
|
// check for tfa authenticators
|
||||||
|
$authenticators = get_tfa($user);
|
||||||
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
|
||||||
|
// authenticators found, init TFA flow
|
||||||
|
$_SESSION['pending_mailcow_cc_username'] = $user;
|
||||||
|
$_SESSION['pending_mailcow_cc_role'] = "user";
|
||||||
|
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => array('logged_in_as', $user)
|
||||||
|
);
|
||||||
|
return "pending";
|
||||||
|
} else if (!isset($authenticators['additional']) || !is_array($authenticators['additional']) || count($authenticators['additional']) == 0) {
|
||||||
|
// no authenticators found, login successfull
|
||||||
|
if (!$is_internal){
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
||||||
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
// skip log
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => array('logged_in_as', $user)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "user";
|
||||||
|
}
|
||||||
|
} elseif ($is_app_passwd) {
|
||||||
|
// password is a app password
|
||||||
|
if ($is_internal){
|
||||||
|
// skip log
|
||||||
|
return "user";
|
||||||
|
}
|
||||||
|
|
||||||
|
$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' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
|
||||||
|
));
|
||||||
|
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
return "user";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function mailcow_domainadmin_login($user, $pass){
|
||||||
|
global $pdo;
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
||||||
|
WHERE `superadmin` = '0'
|
||||||
|
AND `active`='1'
|
||||||
|
AND `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
// verify password
|
||||||
|
if (verify_hash($row['password'], $pass) !== false) {
|
||||||
|
// check for tfa authenticators
|
||||||
|
$authenticators = get_tfa($user);
|
||||||
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
||||||
|
$_SESSION['pending_mailcow_cc_username'] = $user;
|
||||||
|
$_SESSION['pending_mailcow_cc_role'] = "domainadmin";
|
||||||
|
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'info',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => 'awaiting_tfa_confirmation'
|
||||||
|
);
|
||||||
|
return "pending";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
||||||
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => array('logged_in_as', $user)
|
||||||
|
);
|
||||||
|
return "domainadmin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function mailcow_admin_login($user, $pass){
|
||||||
|
global $pdo;
|
||||||
|
|
||||||
|
$user = strtolower(trim($user));
|
||||||
|
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
||||||
|
WHERE `superadmin` = '1'
|
||||||
|
AND `active` = '1'
|
||||||
|
AND `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
// verify password
|
||||||
|
if (verify_hash($row['password'], $pass)) {
|
||||||
|
// check for tfa authenticators
|
||||||
|
$authenticators = get_tfa($user);
|
||||||
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
||||||
|
// active tfa authenticators found, set pending user login
|
||||||
|
$_SESSION['pending_mailcow_cc_username'] = $user;
|
||||||
|
$_SESSION['pending_mailcow_cc_role'] = "admin";
|
||||||
|
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'info',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => 'awaiting_tfa_confirmation'
|
||||||
|
);
|
||||||
|
return "pending";
|
||||||
|
} else {
|
||||||
|
unset($_SESSION['ldelay']);
|
||||||
|
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
||||||
|
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
||||||
|
$stmt->execute(array(':user' => $user));
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $user, '*'),
|
||||||
|
'msg' => array('logged_in_as', $user)
|
||||||
|
);
|
||||||
|
return "admin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keycloak_mbox_login($user, $pass, $is_internal = false){
|
||||||
|
return false;
|
||||||
|
}
|
@ -811,204 +811,6 @@ function verify_hash($hash, $password) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function check_login($user, $pass, $app_passwd_data = false) {
|
|
||||||
global $pdo;
|
|
||||||
global $redis;
|
|
||||||
global $imap_server;
|
|
||||||
|
|
||||||
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => 'malformed_username'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate admin
|
|
||||||
$user = strtolower(trim($user));
|
|
||||||
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
|
||||||
WHERE `superadmin` = '1'
|
|
||||||
AND `active` = '1'
|
|
||||||
AND `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
// verify password
|
|
||||||
if (verify_hash($row['password'], $pass)) {
|
|
||||||
// check for tfa authenticators
|
|
||||||
$authenticators = get_tfa($user);
|
|
||||||
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
|
||||||
// active tfa authenticators found, set pending user login
|
|
||||||
$_SESSION['pending_mailcow_cc_username'] = $user;
|
|
||||||
$_SESSION['pending_mailcow_cc_role'] = "admin";
|
|
||||||
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'info',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => 'awaiting_tfa_confirmation'
|
|
||||||
);
|
|
||||||
return "pending";
|
|
||||||
} else {
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
|
||||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'success',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => array('logged_in_as', $user)
|
|
||||||
);
|
|
||||||
return "admin";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate domain admin
|
|
||||||
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
|
|
||||||
WHERE `superadmin` = '0'
|
|
||||||
AND `active`='1'
|
|
||||||
AND `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
// verify password
|
|
||||||
if (verify_hash($row['password'], $pass) !== false) {
|
|
||||||
// check for tfa authenticators
|
|
||||||
$authenticators = get_tfa($user);
|
|
||||||
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
|
|
||||||
$_SESSION['pending_mailcow_cc_username'] = $user;
|
|
||||||
$_SESSION['pending_mailcow_cc_role'] = "domainadmin";
|
|
||||||
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'info',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => 'awaiting_tfa_confirmation'
|
|
||||||
);
|
|
||||||
return "pending";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
|
||||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'success',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => array('logged_in_as', $user)
|
|
||||||
);
|
|
||||||
return "domainadmin";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate mailbox user
|
|
||||||
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
|
|
||||||
INNER JOIN domain on mailbox.domain = domain.domain
|
|
||||||
WHERE `kind` NOT REGEXP 'location|thing|group'
|
|
||||||
AND `mailbox`.`active`='1'
|
|
||||||
AND `domain`.`active`='1'
|
|
||||||
AND `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
if ($app_passwd_data['eas'] === true) {
|
|
||||||
$stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd`
|
|
||||||
INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox`
|
|
||||||
INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
|
|
||||||
WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group'
|
|
||||||
AND `mailbox`.`active` = '1'
|
|
||||||
AND `domain`.`active` = '1'
|
|
||||||
AND `app_passwd`.`active` = '1'
|
|
||||||
AND `app_passwd`.`eas_access` = '1'
|
|
||||||
AND `app_passwd`.`mailbox` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
}
|
|
||||||
elseif ($app_passwd_data['dav'] === true) {
|
|
||||||
$stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd`
|
|
||||||
INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox`
|
|
||||||
INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
|
|
||||||
WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group'
|
|
||||||
AND `mailbox`.`active` = '1'
|
|
||||||
AND `domain`.`active` = '1'
|
|
||||||
AND `app_passwd`.`active` = '1'
|
|
||||||
AND `app_passwd`.`dav_access` = '1'
|
|
||||||
AND `app_passwd`.`mailbox` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
}
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
// verify password
|
|
||||||
if (verify_hash($row['password'], $pass) !== false) {
|
|
||||||
if (!array_key_exists("app_passwd_id", $row)){
|
|
||||||
// password is not a app password
|
|
||||||
// check for tfa authenticators
|
|
||||||
$authenticators = get_tfa($user);
|
|
||||||
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 &&
|
|
||||||
$app_passwd_data['eas'] !== true && $app_passwd_data['dav'] !== true) {
|
|
||||||
// authenticators found, init TFA flow
|
|
||||||
$_SESSION['pending_mailcow_cc_username'] = $user;
|
|
||||||
$_SESSION['pending_mailcow_cc_role'] = "user";
|
|
||||||
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'success',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => array('logged_in_as', $user)
|
|
||||||
);
|
|
||||||
return "pending";
|
|
||||||
} else if (!isset($authenticators['additional']) || !is_array($authenticators['additional']) || count($authenticators['additional']) == 0) {
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
// no authenticators found, login successfull
|
|
||||||
// Reactivate TFA if it was set to "deactivate TFA for next login"
|
|
||||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
|
|
||||||
$stmt->execute(array(':user' => $user));
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'success',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => array('logged_in_as', $user)
|
|
||||||
);
|
|
||||||
return "user";
|
|
||||||
}
|
|
||||||
} elseif ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) {
|
|
||||||
// password is a app password
|
|
||||||
$service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV';
|
|
||||||
$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' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
|
|
||||||
));
|
|
||||||
|
|
||||||
unset($_SESSION['ldelay']);
|
|
||||||
return "user";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($_SESSION['ldelay'])) {
|
|
||||||
$_SESSION['ldelay'] = "0";
|
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
|
||||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
|
||||||
}
|
|
||||||
elseif (!isset($_SESSION['mailcow_cc_username'])) {
|
|
||||||
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
|
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
|
||||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $user, '*'),
|
|
||||||
'msg' => 'login_failed'
|
|
||||||
);
|
|
||||||
|
|
||||||
sleep($_SESSION['ldelay']);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function formatBytes($size, $precision = 2) {
|
function formatBytes($size, $precision = 2) {
|
||||||
if(!is_numeric($size)) {
|
if(!is_numeric($size)) {
|
||||||
return "0";
|
return "0";
|
||||||
|
@ -1002,6 +1002,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$local_part = strtolower(trim($_data['local_part']));
|
$local_part = strtolower(trim($_data['local_part']));
|
||||||
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
||||||
$username = $local_part . '@' . $domain;
|
$username = $local_part . '@' . $domain;
|
||||||
|
$authsource = 'mailcow';
|
||||||
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@ -1018,6 +1019,9 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (in_array($_data['authsource'], array('mailcow', 'keycloak'))){
|
||||||
|
$authsource = $_data['authsource'];
|
||||||
|
}
|
||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
$name = $local_part;
|
$name = $local_part;
|
||||||
}
|
}
|
||||||
@ -1035,6 +1039,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
||||||
$tags = (isset($_data['tags'])) ? $_data['tags'] : $MAILBOX_DEFAULT_ATTRIBUTES['tags'];
|
$tags = (isset($_data['tags'])) ? $_data['tags'] : $MAILBOX_DEFAULT_ATTRIBUTES['tags'];
|
||||||
$quota_m = (isset($_data['quota'])) ? intval($_data['quota']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['quota']) / 1024 ** 2;
|
$quota_m = (isset($_data['quota'])) ? intval($_data['quota']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['quota']) / 1024 ** 2;
|
||||||
|
if ($authsource != 'mailcow'){
|
||||||
|
$password = '';
|
||||||
|
$password2 = '';
|
||||||
|
$password_hashed = '';
|
||||||
|
}
|
||||||
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@ -1153,10 +1162,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (password_check($password, $password2) !== true) {
|
if ($authsource == 'mailcow'){
|
||||||
return false;
|
if (password_check($password, $password2) !== true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$password_hashed = hash_password($password);
|
||||||
}
|
}
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
|
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@ -1182,8 +1193,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `active`)
|
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `authsource`, `active`)
|
||||||
VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :active)");
|
VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :authsource, :active)");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $username,
|
':username' => $username,
|
||||||
':password_hashed' => $password_hashed,
|
':password_hashed' => $password_hashed,
|
||||||
@ -1192,6 +1203,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':local_part' => $local_part,
|
':local_part' => $local_part,
|
||||||
':domain' => $domain,
|
':domain' => $domain,
|
||||||
':mailbox_attrs' => $mailbox_attrs,
|
':mailbox_attrs' => $mailbox_attrs,
|
||||||
|
':authsource' => $authsource,
|
||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
$stmt = $pdo->prepare("UPDATE `mailbox` SET
|
$stmt = $pdo->prepare("UPDATE `mailbox` SET
|
||||||
@ -4422,6 +4434,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`mailbox`.`quota`,
|
`mailbox`.`quota`,
|
||||||
`mailbox`.`created`,
|
`mailbox`.`created`,
|
||||||
`mailbox`.`modified`,
|
`mailbox`.`modified`,
|
||||||
|
`mailbox`.`authsource`,
|
||||||
`quota2`.`bytes`,
|
`quota2`.`bytes`,
|
||||||
`attributes`,
|
`attributes`,
|
||||||
`custom_attributes`,
|
`custom_attributes`,
|
||||||
@ -4443,6 +4456,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`mailbox`.`quota`,
|
`mailbox`.`quota`,
|
||||||
`mailbox`.`created`,
|
`mailbox`.`created`,
|
||||||
`mailbox`.`modified`,
|
`mailbox`.`modified`,
|
||||||
|
`mailbox`.`authsource`,
|
||||||
`quota2replica`.`bytes`,
|
`quota2replica`.`bytes`,
|
||||||
`attributes`,
|
`attributes`,
|
||||||
`custom_attributes`,
|
`custom_attributes`,
|
||||||
@ -4472,6 +4486,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||||
$mailboxdata['created'] = $row['created'];
|
$mailboxdata['created'] = $row['created'];
|
||||||
$mailboxdata['modified'] = $row['modified'];
|
$mailboxdata['modified'] = $row['modified'];
|
||||||
|
$mailboxdata['authsource'] = ($row['authsource']) ? $row['authsource'] : 'mailcow';
|
||||||
|
|
||||||
if ($mailboxdata['percent_in_use'] === '- ') {
|
if ($mailboxdata['percent_in_use'] === '- ') {
|
||||||
$mailboxdata['percent_class'] = "info";
|
$mailboxdata['percent_class'] = "info";
|
||||||
|
@ -362,6 +362,7 @@ function init_db_schema() {
|
|||||||
"custom_attributes" => "JSON NOT NULL DEFAULT ('{}')",
|
"custom_attributes" => "JSON NOT NULL DEFAULT ('{}')",
|
||||||
"kind" => "VARCHAR(100) NOT NULL DEFAULT ''",
|
"kind" => "VARCHAR(100) NOT NULL DEFAULT ''",
|
||||||
"multiple_bookings" => "INT NOT NULL DEFAULT -1",
|
"multiple_bookings" => "INT NOT NULL DEFAULT -1",
|
||||||
|
"authsource" => "ENUM('mailcow', 'keycloak') DEFAULT 'mailcow'",
|
||||||
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||||
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
||||||
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
|
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
|
||||||
|
@ -177,6 +177,7 @@ function get_remote_ip() {
|
|||||||
|
|
||||||
// Load core functions first
|
// Load core functions first
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
||||||
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.auth.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
||||||
|
|
||||||
// IMAP lib
|
// IMAP lib
|
||||||
|
@ -401,6 +401,26 @@ if (isset($_GET['query'])) {
|
|||||||
);
|
);
|
||||||
echo json_encode($return);
|
echo json_encode($return);
|
||||||
break;
|
break;
|
||||||
|
case "login":
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$post = trim(file_get_contents('php://input'));
|
||||||
|
if ($post) {
|
||||||
|
$post = json_decode($post, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = array("success" => false, "role" => false);
|
||||||
|
if(!isset($post['username']) || !isset($post['password'])){
|
||||||
|
echo json_encode($return);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$result = check_login($post['username'], $post['password'], $post['protocol']);
|
||||||
|
if ($result) {
|
||||||
|
$return = array("success" => true, "role" => $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($return);
|
||||||
|
return;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "get":
|
case "get":
|
||||||
|
@ -11,7 +11,8 @@ $session_var_pass = 'sogo-sso-pass';
|
|||||||
// validate credentials for basic auth requests
|
// validate credentials for basic auth requests
|
||||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||||
// load prerequisites only when required
|
// load prerequisites only when required
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
||||||
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.auth.inc.php';
|
||||||
$username = $_SERVER['PHP_AUTH_USER'];
|
$username = $_SERVER['PHP_AUTH_USER'];
|
||||||
$password = $_SERVER['PHP_AUTH_PW'];
|
$password = $_SERVER['PHP_AUTH_PW'];
|
||||||
$is_eas = false;
|
$is_eas = false;
|
||||||
|
@ -24,7 +24,13 @@
|
|||||||
<input type="hidden" value="default" name="sender_acl">
|
<input type="hidden" value="default" name="sender_acl">
|
||||||
<input type="hidden" value="0" name="force_pw_update">
|
<input type="hidden" value="0" name="force_pw_update">
|
||||||
<input type="hidden" value="0" name="sogo_access">
|
<input type="hidden" value="0" name="sogo_access">
|
||||||
<input type="hidden" value="0" name="protocol_access">
|
<input type="hidden" value="0" name="protocol_access">
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label class="control-label col-sm-2">{{ lang.edit.full_name }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<span>{{ result.authsource }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
|
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -28,6 +28,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="authsource">{{ lang.add.domain }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="full-width-select" data-live-search="true" id="addAuthsource" name="authsource" required>
|
||||||
|
<option selected>mailcow</option>
|
||||||
|
<option>keycloak</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="name">{{ lang.add.full_name }}</label>
|
<label class="control-label col-sm-2 text-sm-end text-sm-end" for="name">{{ lang.add.full_name }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
Reference in New Issue
Block a user