public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
[Web] Fix authentication when mailbox or domain is deactivated
cb08132a
data/web/inc/functions.auth.inc.php | 56 +++++++++++++++++++++++++++++++----
data/web/inc/functions.inc.php | 59 +++++++++++++++++++++++++++++++++----
2 files changed, 103 insertions(+), 12 deletions(-)
Diff
diff --git a/data/web/inc/functions.auth.inc.php b/data/web/inc/functions.auth.inc.php
index e047b83b..7fd535be 100644
--- a/data/web/inc/functions.auth.inc.php
+++ b/data/web/inc/functions.auth.inc.php
@@ -178,25 +178,40 @@ function user_login($user, $pass, $extra = null){
return false;
}
- $stmt = $pdo->prepare("SELECT * FROM `mailbox`
+ $stmt = $pdo->prepare("SELECT
+ mailbox.*,
+ domain.active AS d_active
+ FROM `mailbox`
INNER JOIN domain on mailbox.domain = domain.domain
WHERE `kind` NOT REGEXP 'location|thing|group'
- AND `domain`.`active`='1'
AND `username` = :user");
$stmt->execute(array(':user' => $user));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
// user does not exist, try call idp login and create user if possible via rest flow
if (!$row){
+ $result = false;
if ($iam_settings['authsource'] == 'keycloak' && intval($iam_settings['mailpassword_flow']) == 1){
$result = keycloak_mbox_login_rest($user, $pass, array('is_internal' => $is_internal, 'create' => true));
- if ($result !== false) return $result;
} else if ($iam_settings['authsource'] == 'ldap') {
$result = ldap_mbox_login($user, $pass, array('is_internal' => $is_internal, 'create' => true));
- if ($result !== false) return $result;
}
- }
- if ($row['active'] != 1) {
+ if ($result !== false){
+ // double check if mailbox is active
+ $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 `username` = :user");
+ $stmt->execute(array(':user' => $user));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!empty($row)) {
+ return true;
+ }
+ }
+ clear_session();
return false;
}
@@ -206,6 +221,19 @@ function user_login($user, $pass, $extra = null){
if (intval($iam_settings['mailpassword_flow']) == 1){
$result = keycloak_mbox_login_rest($user, $pass, array('is_internal' => $is_internal));
if ($result !== false) {
+ // double check if mailbox and domain is active
+ $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 `username` = :user");
+ $stmt->execute(array(':user' => $user));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (empty($row)) {
+ return false;
+ }
+
// check for tfa authenticators
$authenticators = get_tfa($user);
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
@@ -245,6 +273,19 @@ function user_login($user, $pass, $extra = null){
// user authsource is ldap
$result = ldap_mbox_login($user, $pass, array('is_internal' => $is_internal));
if ($result !== false) {
+ // double check if mailbox and domain is active
+ $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 `username` = :user");
+ $stmt->execute(array(':user' => $user));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (empty($row)) {
+ return false;
+ }
+
// check for tfa authenticators
$authenticators = get_tfa($user);
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
@@ -278,6 +319,9 @@ function user_login($user, $pass, $extra = null){
return $result;
break;
case 'mailcow':
+ if ($row['active'] != 1 || $row['d_active'] != 1) {
+ return false;
+ }
// verify password
if (verify_hash($row['password'], $pass) !== false) {
// check for tfa authenticators
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 187036b4..5b67dd1e 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -2653,17 +2653,25 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
$mapper_key = array_search($user_template, $iam_settings['mappers']);
// token valid, get mailbox
- $stmt = $pdo->prepare("SELECT * FROM `mailbox`
+ $stmt = $pdo->prepare("SELECT
+ mailbox.*,
+ domain.active AS d_active
+ 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
- AND (`authsource`='keycloak' OR `authsource`='generic-oidc')");
+ AND `username` = :user");
$stmt->execute(array(':user' => $info['email']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row){
- // success
+ if (!in_array($row['authsource'], array("keycloak", "generic-oidc"))) {
+ clear_session();
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $info['email'], "The user's authentication source is not of type OIDC"),
+ 'msg' => 'login_failed'
+ );
+ return false;
+ }
if ($mapper_key !== false) {
// update user
$_SESSION['access_all_exception'] = '1';
@@ -2673,6 +2681,26 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
'template' => $iam_settings['templates'][$mapper_key]
));
$_SESSION['access_all_exception'] = '0';
+
+ // get updated row
+ $stmt = $pdo->prepare("SELECT
+ mailbox.*,
+ domain.active AS d_active
+ FROM `mailbox`
+ INNER JOIN domain on mailbox.domain = domain.domain
+ WHERE `kind` NOT REGEXP 'location|thing|group'
+ AND `username` = :user");
+ $stmt->execute(array(':user' => $info['email']));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ }
+ if ($row['active'] != 1 || $row['d_active'] != 1) {
+ clear_session();
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $info['email'], 'Domain or mailbox is inactive'),
+ 'msg' => 'login_failed'
+ );
+ return false;
}
set_user_loggedin_session($info['email']);
$_SESSION['iam_token'] = $plain_token;
@@ -2715,6 +2743,25 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
return false;
}
+ // double check if mailbox and domain is active
+ $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 `username` = :user");
+ $stmt->execute(array(':user' => $info['email']));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (empty($row)) {
+ clear_session();
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $info['email'], 'Domain or mailbox is inactive'),
+ 'msg' => 'login_failed'
+ );
+ return false;
+ }
+
set_user_loggedin_session($info['email']);
$_SESSION['iam_token'] = $plain_token;
$_SESSION['iam_refresh_token'] = $plain_refreshtoken;