Merge branch 'master' into gnous
This commit is contained in:
commit
bb7d4c9785
8
.gitignore
vendored
8
.gitignore
vendored
@ -7,6 +7,7 @@
|
||||
data/assets/ejabberd/sqlite/sqlite.db
|
||||
data/assets/ssl-example/*
|
||||
data/assets/ssl/*
|
||||
data/conf/borgmatic/
|
||||
data/conf/clamav/whitelist.ign2
|
||||
data/conf/dovecot/acl_anyone
|
||||
data/conf/dovecot/dovecot-master.passwd
|
||||
@ -39,12 +40,17 @@ data/conf/postfix/sql
|
||||
data/conf/rspamd/custom/*
|
||||
data/conf/rspamd/local.d/*
|
||||
data/conf/rspamd/override.d/*
|
||||
data/conf/sogo/custom-theme.js
|
||||
data/conf/sogo/plist_ldap
|
||||
data/conf/sogo/sieve.creds
|
||||
data/conf/sogo/sogo-full.svg
|
||||
data/gitea/
|
||||
data/gogs/
|
||||
data/hooks/
|
||||
data/hooks/dovecot
|
||||
data/hooks/phpfpm
|
||||
data/hooks/postfix
|
||||
data/hooks/rspamd
|
||||
data/hooks/unbound
|
||||
data/web/.well-known/acme-challenge
|
||||
data/web/css/build/0081-custom-mailcow.css
|
||||
data/web/inc/vars.local.inc.php
|
||||
|
@ -155,6 +155,18 @@ while true; do
|
||||
fi
|
||||
if [[ ! -f ${ACME_BASE}/acme/account.pem ]]; then
|
||||
log_f "Generating missing Lets Encrypt account key..."
|
||||
if [[ ! -z ${ACME_CONTACT} ]]; then
|
||||
if ! verify_email "${ACME_CONTACT}"; then
|
||||
log_f "Invalid email address, will not start registration!"
|
||||
sleep 365d
|
||||
exec $(readlink -f "$0")
|
||||
else
|
||||
ACME_CONTACT_PARAMETER="--contact mailto:${ACME_CONTACT}"
|
||||
log_f "Valid email address, using ${ACME_CONTACT} for registration"
|
||||
fi
|
||||
else
|
||||
ACME_CONTACT_PARAMETER=""
|
||||
fi
|
||||
openssl genrsa 4096 > ${ACME_BASE}/acme/account.pem
|
||||
else
|
||||
log_f "Using existing Lets Encrypt account key ${ACME_BASE}/acme/account.pem"
|
||||
@ -207,22 +219,9 @@ while true; do
|
||||
IPV6=$(get_ipv6)
|
||||
log_f "OK: ${IPV4}, ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}"
|
||||
|
||||
# Hard-fail on CAA errors for MAILCOW_HOSTNAME
|
||||
MH_PARENT_DOMAIN=$(echo ${MAILCOW_HOSTNAME} | cut -d. -f2-)
|
||||
MH_CAAS=( $(dig CAA ${MH_PARENT_DOMAIN} +short | sed -n 's/\d issue "\(.*\)"/\1/p') )
|
||||
if [[ ! -z ${MH_CAAS} ]]; then
|
||||
if [[ ${MH_CAAS[@]} =~ "letsencrypt.org" ]]; then
|
||||
log_f "Validated CAA for parent domain ${MH_PARENT_DOMAIN}"
|
||||
else
|
||||
log_f "Skipping ACME validation: Lets Encrypt disallowed for ${MAILCOW_HOSTNAME} by CAA record, retrying in 1h..."
|
||||
sleep 1h
|
||||
exec $(readlink -f "$0")
|
||||
fi
|
||||
fi
|
||||
|
||||
#########################################
|
||||
# IP and webroot challenge verification #
|
||||
SQL_DOMAINS=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0" -Bs)
|
||||
SQL_DOMAINS=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs)
|
||||
if [[ ! $? -eq 0 ]]; then
|
||||
log_f "Failed to read SQL domains, retrying in 1 minute..."
|
||||
sleep 1m
|
||||
@ -290,7 +289,7 @@ while true; do
|
||||
VALIDATED_CERTIFICATES+=("${CERT_NAME}")
|
||||
|
||||
# obtain server certificate if required
|
||||
DOMAINS=${SERVER_SAN_VALIDATED[@]} /srv/obtain-certificate.sh rsa
|
||||
ACME_CONTACT_PARAMETER=${ACME_CONTACT_PARAMETER} DOMAINS=${SERVER_SAN_VALIDATED[@]} /srv/obtain-certificate.sh rsa
|
||||
RETURN="$?"
|
||||
if [[ "$RETURN" == "0" ]]; then # 0 = cert created successfully
|
||||
CERT_AMOUNT_CHANGED=1
|
||||
|
@ -16,6 +16,15 @@ log_f() {
|
||||
fi
|
||||
}
|
||||
|
||||
verify_email(){
|
||||
regex="^(([A-Za-z0-9]+((\.|\-|\_|\+)?[A-Za-z0-9]?)*[A-Za-z0-9]+)|[A-Za-z0-9]+)@(([A-Za-z0-9]+)+((\.|\-|\_)?([A-Za-z0-9]+)+)*)+\.([A-Za-z]{2,})+$"
|
||||
if [[ $1 =~ ${regex} ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
verify_hash_match(){
|
||||
CERT_HASH=$(openssl x509 -in "${1}" -noout -pubkey | openssl md5)
|
||||
KEY_HASH=$(openssl pkey -in "${2}" -pubout | openssl md5)
|
||||
@ -60,6 +69,17 @@ check_domain(){
|
||||
DOMAIN=$1
|
||||
A_DOMAIN=$(dig A ${DOMAIN} +short | tail -n 1)
|
||||
AAAA_DOMAIN=$(dig AAAA ${DOMAIN} +short | tail -n 1)
|
||||
# Hard-fail on CAA errors for MAILCOW_HOSTNAME
|
||||
PARENT_DOMAIN=$(echo ${DOMAIN} | cut -d. -f2-)
|
||||
CAAS=( $(dig CAA ${PARENT_DOMAIN} +short | sed -n 's/\d issue "\(.*\)"/\1/p') )
|
||||
if [[ ! -z ${CAAS} ]]; then
|
||||
if [[ ${CAAS[@]} =~ "letsencrypt.org" ]]; then
|
||||
log_f "Validated CAA for parent domain ${PARENT_DOMAIN}"
|
||||
else
|
||||
log_f "Lets Encrypt disallowed for ${PARENT_DOMAIN} by CAA record"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
# Check if CNAME without v6 enabled target
|
||||
if [[ ! -z ${AAAA_DOMAIN} ]] && [[ -z $(echo ${AAAA_DOMAIN} | grep "^\([0-9a-fA-F]\{0,4\}:\)\{1,7\}[0-9a-fA-F]\{0,4\}$") ]]; then
|
||||
AAAA_DOMAIN=
|
||||
|
@ -93,8 +93,8 @@ until dig letsencrypt.org +time=3 +tries=1 @unbound > /dev/null; do
|
||||
sleep 2
|
||||
done
|
||||
log_f "Resolver OK"
|
||||
|
||||
ACME_RESPONSE=$(acme-tiny ${DIRECTORY_URL} \
|
||||
log_f "Using command acme-tiny ${DIRECTORY_URL} ${ACME_CONTACT_PARAMETER} --account-key ${ACME_BASE}/acme/account.pem --disable-check --csr ${CSR} --acme-dir /var/www/acme/"
|
||||
ACME_RESPONSE=$(acme-tiny ${DIRECTORY_URL} ${ACME_CONTACT_PARAMETER} \
|
||||
--account-key ${ACME_BASE}/acme/account.pem \
|
||||
--disable-check \
|
||||
--csr ${CSR} \
|
||||
|
@ -2,7 +2,7 @@ FROM debian:buster-slim
|
||||
|
||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||
|
||||
ARG CLAMAV=0.103.0
|
||||
ARG CLAMAV=0.103.2
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
|
@ -2,8 +2,9 @@ FROM debian:buster-slim
|
||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG DOVECOT=2.3.13
|
||||
ARG DOVECOT=2.3.14
|
||||
ENV LC_ALL C
|
||||
ENV GOSU_VERSION 1.12
|
||||
|
||||
# Add groups and users before installing Dovecot to not break compatibility
|
||||
RUN groupadd -g 5000 vmail \
|
||||
@ -20,7 +21,6 @@ RUN groupadd -g 5000 vmail \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
cpanminus \
|
||||
cron \
|
||||
curl \
|
||||
dnsutils \
|
||||
dirmngr \
|
||||
@ -82,6 +82,11 @@ RUN groupadd -g 5000 vmail \
|
||||
syslog-ng \
|
||||
syslog-ng-core \
|
||||
syslog-ng-mod-redis \
|
||||
wget \
|
||||
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
|
||||
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
|
||||
&& chmod +x /usr/local/bin/gosu \
|
||||
&& gosu nobody true \
|
||||
&& apt-key adv --fetch-keys https://repo.dovecot.org/DOVECOT-REPO-GPG \
|
||||
&& echo "deb https://repo.dovecot.org/ce-${DOVECOT}/debian/buster buster main" > /etc/apt/sources.list.d/dovecot.list \
|
||||
&& apt-get update \
|
||||
@ -100,7 +105,7 @@ RUN groupadd -g 5000 vmail \
|
||||
&& apt-get autoremove --purge -y \
|
||||
&& apt-get autoclean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& rm -rf /tmp/* /var/tmp/* /etc/cron.daily/* /root/.cache/
|
||||
&& rm -rf /tmp/* /var/tmp/* /root/.cache/
|
||||
|
||||
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
||||
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
|
||||
@ -108,7 +113,7 @@ COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
||||
COPY imapsync /usr/local/bin/imapsync
|
||||
COPY postlogin.sh /usr/local/bin/postlogin.sh
|
||||
COPY imapsync_cron.pl /usr/local/bin/imapsync_cron.pl
|
||||
COPY imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
|
||||
COPY report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
|
||||
COPY report-ham.sieve /usr/lib/dovecot/sieve/report-ham.sieve
|
||||
COPY rspamd-pipe-ham /usr/lib/dovecot/sieve/rspamd-pipe-ham
|
||||
|
@ -7,7 +7,7 @@ while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${D
|
||||
sleep 2
|
||||
done
|
||||
|
||||
until dig +short mailcow.email @unbound > /dev/null; do
|
||||
until dig +short mailcow.email > /dev/null; do
|
||||
echo "Waiting for DNS..."
|
||||
sleep 1
|
||||
done
|
||||
@ -185,6 +185,12 @@ function script_deinit()
|
||||
end
|
||||
EOF
|
||||
|
||||
# Replace patterns in app-passdb.lua
|
||||
sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/app-passdb.lua
|
||||
sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/app-passdb.lua
|
||||
sed -i "s/__DBNAME__/${DBNAME}/g" /etc/dovecot/lua/app-passdb.lua
|
||||
|
||||
|
||||
# Migrate old sieve_after file
|
||||
[[ -f /etc/dovecot/sieve_after ]] && mv /etc/dovecot/sieve_after /etc/dovecot/global_sieve_after
|
||||
# Create global sieve scripts
|
||||
@ -269,15 +275,10 @@ else
|
||||
rm -f /etc/dovecot/sogo-sso.conf
|
||||
fi
|
||||
|
||||
# Hard-code env vars to scripts due to cron not passing them to the scripts
|
||||
sed -i "s/__DBUSER__/${DBUSER}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /etc/dovecot/lua/app-passdb.lua
|
||||
sed -i "s/__DBPASS__/${DBPASS}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /etc/dovecot/lua/app-passdb.lua
|
||||
sed -i "s/__DBNAME__/${DBNAME}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /etc/dovecot/lua/app-passdb.lua
|
||||
sed -i "s/__MAILCOW_HOSTNAME__/${MAILCOW_HOSTNAME}/g" /usr/local/bin/quarantine_notify.py
|
||||
sed -i "s/__LOG_LINES__/${LOG_LINES}/g" /usr/local/bin/trim_logs.sh
|
||||
|
||||
if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
|
||||
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
||||
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
||||
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
||||
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
sys.exit()
|
||||
@ -311,7 +312,7 @@ chmod g+rw /dev/console
|
||||
chown root:tty /dev/console
|
||||
chmod +x /usr/lib/dovecot/sieve/rspamd-pipe-ham \
|
||||
/usr/lib/dovecot/sieve/rspamd-pipe-spam \
|
||||
/usr/local/bin/imapsync_cron.pl \
|
||||
/usr/local/bin/imapsync_runner.pl \
|
||||
/usr/local/bin/postlogin.sh \
|
||||
/usr/local/bin/imapsync \
|
||||
/usr/local/bin/trim_logs.sh \
|
||||
@ -322,27 +323,6 @@ chmod +x /usr/lib/dovecot/sieve/rspamd-pipe-ham \
|
||||
/usr/local/bin/quota_notify.py \
|
||||
/usr/local/bin/repl_health.sh
|
||||
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
# Setup cronjobs
|
||||
echo '* * * * * nobody /usr/local/bin/imapsync_cron.pl 2>&1 | /usr/bin/logger' > /etc/cron.d/imapsync
|
||||
#echo '30 3 * * * vmail /usr/local/bin/doveadm quota recalc -A' > /etc/cron.d/dovecot-sync
|
||||
echo '* * * * * vmail /usr/local/bin/trim_logs.sh >> /dev/console 2>&1' > /etc/cron.d/trim_logs
|
||||
echo '25 * * * * vmail /usr/local/bin/maildir_gc.sh >> /dev/console 2>&1' > /etc/cron.d/maildir_gc
|
||||
echo '30 1 * * * root /usr/local/bin/sa-rules.sh >> /dev/console 2>&1' > /etc/cron.d/sa-rules
|
||||
echo '0 2 * * * root /usr/bin/curl http://solr:8983/solr/dovecot-fts/update?optimize=true >> /dev/console 2>&1' > /etc/cron.d/solr-optimize
|
||||
echo '*/20 * * * * vmail /usr/local/bin/quarantine_notify.py >> /dev/console 2>&1' > /etc/cron.d/quarantine_notify
|
||||
echo '15 4 * * * vmail /usr/local/bin/clean_q_aged.sh >> /dev/console 2>&1' > /etc/cron.d/clean_q_aged
|
||||
echo '*/5 * * * * vmail /usr/local/bin/repl_health.sh >> /dev/console 2>&1' > /etc/cron.d/repl_health
|
||||
else
|
||||
echo '25 * * * * vmail /usr/local/bin/maildir_gc.sh >> /dev/console 2>&1' > /etc/cron.d/maildir_gc
|
||||
echo '30 1 * * * root /usr/local/bin/sa-rules.sh >> /dev/console 2>&1' > /etc/cron.d/sa-rules
|
||||
echo '0 2 * * * root /usr/bin/curl http://solr:8983/solr/dovecot-fts/update?optimize=true >> /dev/console 2>&1' > /etc/cron.d/solr-optimize
|
||||
echo '*/5 * * * * vmail /usr/local/bin/repl_health.sh >> /dev/console 2>&1' > /etc/cron.d/repl_health
|
||||
fi
|
||||
|
||||
# Fix more than 1 hardlink issue
|
||||
touch /etc/crontab /etc/cron.*/*
|
||||
|
||||
# Prepare environment file for cronjobs
|
||||
printenv | sed 's/^\(.*\)$/export \1/g' > /source_env.sh
|
||||
|
||||
|
@ -36,11 +36,11 @@ sub qqw($) {
|
||||
}
|
||||
|
||||
$run_dir="/tmp";
|
||||
$dsn = 'DBI:mysql:database=__DBNAME__;mysql_socket=/var/run/mysqld/mysqld.sock';
|
||||
$dsn = 'DBI:mysql:database=' . $ENV{'DBNAME'} . ';mysql_socket=/var/run/mysqld/mysqld.sock';
|
||||
$lock_file = $run_dir . "/imapsync_busy";
|
||||
$lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1);
|
||||
$lockmgr->lock($lock_file) || die "can't lock ${lock_file}";
|
||||
$dbh = DBI->connect($dsn, '__DBUSER__', '__DBPASS__', {
|
||||
$dbh = DBI->connect($dsn, $ENV{'DBUSER'}, $ENV{'DBPASS'}, {
|
||||
mysql_auto_reconnect => 1,
|
||||
mysql_enable_utf8mb4 => 1
|
||||
});
|
||||
@ -127,6 +127,7 @@ while ($row = $sth->fetchrow_arrayref()) {
|
||||
my $generated_cmds = [ "/usr/local/bin/imapsync",
|
||||
"--tmpdir", "/tmp",
|
||||
"--nofoldersizes",
|
||||
"--addheader",
|
||||
($timeout1 gt "0" ? () : ('--timeout1', $timeout1)),
|
||||
($timeout2 gt "0" ? () : ('--timeout2', $timeout2)),
|
||||
($exclude eq "" ? () : ("--exclude", $exclude)),
|
@ -1,2 +1,2 @@
|
||||
#/bin/bash
|
||||
#!/bin/bash
|
||||
[ -d /var/vmail/_garbage/ ] && /usr/bin/find /var/vmail/_garbage/ -mindepth 1 -maxdepth 1 -type d -cmin +${MAILDIR_GC_TIME} -exec rm -r {} \;
|
||||
|
@ -41,7 +41,7 @@ try:
|
||||
break
|
||||
|
||||
time_now = int(time.time())
|
||||
mailcow_hostname = '__MAILCOW_HOSTNAME__'
|
||||
mailcow_hostname = os.environ.get('MAILCOW_HOSTNAME')
|
||||
|
||||
max_score = float(r.get('Q_MAX_SCORE') or "9999.0")
|
||||
if max_score == "":
|
||||
@ -50,7 +50,7 @@ try:
|
||||
def query_mysql(query, headers = True, update = False):
|
||||
while True:
|
||||
try:
|
||||
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user='__DBUSER__', passwd='__DBPASS__', database='__DBNAME__', charset="utf8")
|
||||
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8")
|
||||
except Exception as ex:
|
||||
print('%s - trying again...' % (ex))
|
||||
time.sleep(3)
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
# Create temp directories
|
||||
[[ ! -d /tmp/sa-rules-heinlein ]] && mkdir -p /tmp/sa-rules-heinlein
|
||||
#[[ ! -d /tmp/sa-rules-schaal ]] && mkdir -p /tmp/sa-rules-schaal
|
||||
|
||||
# Hash current SA rules
|
||||
if [[ ! -f /etc/rspamd/custom/sa-rules ]]; then
|
||||
@ -12,19 +11,11 @@ else
|
||||
fi
|
||||
|
||||
# Deploy
|
||||
## Heinlein
|
||||
curl --connect-timeout 15 --retry 10 --max-time 30 http://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"').tar.gz --output /tmp/sa-rules-heinlein.tar.gz
|
||||
curl --connect-timeout 15 --retry 10 --max-time 30 http://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz
|
||||
if gzip -t /tmp/sa-rules-heinlein.tar.gz; then
|
||||
tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein
|
||||
cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules
|
||||
fi
|
||||
## Schaal
|
||||
#curl --connect-timeout 15 --max-time 30 http://sa.schaal-it.net/$(dig txt 1.4.3.sa.schaal-it.net +short | tr -d '"').tar.gz --output /tmp/sa-rules-schaal.tar.gz
|
||||
#if gzip -t /tmp/sa-rules-schaal.tar.gz; then
|
||||
# tar xfvz /tmp/sa-rules-schaal.tar.gz -C /tmp/sa-rules-schaal
|
||||
# # Append, do not overwrite
|
||||
# cat /tmp/sa-rules-schaal/*cf >> /etc/rspamd/custom/sa-rules
|
||||
#fi
|
||||
|
||||
sed -i -e 's/\([^\\]\)\$\([^\/]\)/\1\\$\2/g' /etc/rspamd/custom/sa-rules
|
||||
|
||||
@ -40,4 +31,3 @@ fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf /tmp/sa-rules-heinlein /tmp/sa-rules-heinlein.tar.gz
|
||||
#rm -rf /tmp/sa-rules-schaal /tmp/sa-rules-schaal.tar.gz
|
||||
|
@ -15,10 +15,6 @@ autostart=true
|
||||
command=/usr/sbin/dovecot -F
|
||||
autorestart=true
|
||||
|
||||
[program:cron]
|
||||
command=/usr/sbin/cron -f
|
||||
autorestart=true
|
||||
|
||||
[eventlistener:processes]
|
||||
command=/usr/local/sbin/stop-supervisor.sh
|
||||
events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL
|
||||
|
@ -27,7 +27,7 @@ destination d_redis_f2b_channel {
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
filter f_mail { facility(mail); };
|
||||
|
@ -27,7 +27,7 @@ destination d_redis_f2b_channel {
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
filter f_mail { facility(mail); };
|
||||
|
@ -14,12 +14,12 @@ if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
else
|
||||
REDIS_CMDLINE="redis-cli -h redis -p 6379"
|
||||
fi
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM DOVECOT_MAILLOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM SOGO_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM NETFILTER_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM AUTODISCOVER_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM API_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM RL_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM WATCHDOG_LOG 0 __LOG_LINES__"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM DOVECOT_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM SOGO_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM NETFILTER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
|
||||
|
@ -8,7 +8,7 @@ use LeeSherwood\Ejabberd\CommandExecutors\mailcowCommandExecutor;
|
||||
|
||||
$logger = new Logger('ejabberdAuth');
|
||||
|
||||
$stdoutHandler = new Monolog\Handler\StreamHandler('/var/www/authentication/auth.log', Logger::DEBUG);
|
||||
$stdoutHandler = new Monolog\Handler\StreamHandler('/var/www/authentication/auth.log', Logger::INFO);
|
||||
|
||||
$logger->pushHandler($stdoutHandler);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
until dig +short mailcow.email @unbound > /dev/null; do
|
||||
until dig +short mailcow.email > /dev/null; do
|
||||
echo "Waiting for DNS..."
|
||||
sleep 1
|
||||
done
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import atexit
|
||||
import signal
|
||||
@ -39,6 +40,7 @@ BLACKLIST= []
|
||||
bans = {}
|
||||
|
||||
quit_now = False
|
||||
exit_code = 0
|
||||
lock = Lock()
|
||||
|
||||
def log(priority, message):
|
||||
@ -61,6 +63,7 @@ def logInfo(message):
|
||||
def refreshF2boptions():
|
||||
global f2boptions
|
||||
global quit_now
|
||||
global exit_code
|
||||
if not r.get('F2B_OPTIONS'):
|
||||
f2boptions = {}
|
||||
f2boptions['ban_time'] = int
|
||||
@ -81,10 +84,12 @@ def refreshF2boptions():
|
||||
except ValueError:
|
||||
print('Error loading F2B options: F2B_OPTIONS is not json')
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
|
||||
def refreshF2bregex():
|
||||
global f2bregex
|
||||
global quit_now
|
||||
global exit_code
|
||||
if not r.get('F2B_REGEX'):
|
||||
f2bregex = {}
|
||||
f2bregex[1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
|
||||
@ -95,6 +100,7 @@ def refreshF2bregex():
|
||||
f2bregex[6] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||
f2bregex[7] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
||||
f2bregex[8] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
f2bregex[9] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
|
||||
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||
else:
|
||||
try:
|
||||
@ -103,6 +109,7 @@ def refreshF2bregex():
|
||||
except ValueError:
|
||||
print('Error loading F2B options: F2B_REGEX is not json')
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
|
||||
if r.exists('F2B_LOG'):
|
||||
r.rename('F2B_LOG', 'NETFILTER_LOG')
|
||||
@ -110,6 +117,7 @@ if r.exists('F2B_LOG'):
|
||||
def mailcowChainOrder():
|
||||
global lock
|
||||
global quit_now
|
||||
global exit_code
|
||||
while not quit_now:
|
||||
time.sleep(10)
|
||||
with lock:
|
||||
@ -128,9 +136,11 @@ def mailcowChainOrder():
|
||||
if position > 2:
|
||||
logCrit('Error in %s chain order: MAILCOW on position %d, restarting container' % (chain.name, position))
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
if not target_found:
|
||||
logCrit('Error in %s chain: MAILCOW target not found, restarting container' % (chain.name))
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
|
||||
def ban(address):
|
||||
global lock
|
||||
@ -300,22 +310,30 @@ def watch():
|
||||
logInfo('Watching Redis channel F2B_CHANNEL')
|
||||
pubsub.subscribe('F2B_CHANNEL')
|
||||
|
||||
global quit_now
|
||||
global exit_code
|
||||
|
||||
while not quit_now:
|
||||
for item in pubsub.listen():
|
||||
refreshF2bregex()
|
||||
for rule_id, rule_regex in f2bregex.items():
|
||||
if item['data'] and item['type'] == 'message':
|
||||
try:
|
||||
result = re.search(rule_regex, item['data'])
|
||||
except re.error:
|
||||
result = False
|
||||
if result:
|
||||
addr = result.group(1)
|
||||
ip = ipaddress.ip_address(addr)
|
||||
if ip.is_private or ip.is_loopback:
|
||||
continue
|
||||
logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
|
||||
ban(addr)
|
||||
try:
|
||||
for item in pubsub.listen():
|
||||
refreshF2bregex()
|
||||
for rule_id, rule_regex in f2bregex.items():
|
||||
if item['data'] and item['type'] == 'message':
|
||||
try:
|
||||
result = re.search(rule_regex, item['data'])
|
||||
except re.error:
|
||||
result = False
|
||||
if result:
|
||||
addr = result.group(1)
|
||||
ip = ipaddress.ip_address(addr)
|
||||
if ip.is_private or ip.is_loopback:
|
||||
continue
|
||||
logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
|
||||
ban(addr)
|
||||
except Exception as ex:
|
||||
logWarn('Error reading log line from pubsub')
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
|
||||
def snat4(snat_target):
|
||||
global lock
|
||||
@ -555,3 +573,5 @@ if __name__ == '__main__':
|
||||
|
||||
while not quit_now:
|
||||
time.sleep(0.5)
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
@ -90,6 +90,15 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
${REDIS_CMDLINE} --raw SET Q_MAX_AGE 365
|
||||
fi
|
||||
|
||||
# Set default password policy - if unset
|
||||
if [[ -z $(${REDIS_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY length 6
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY chars 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
|
||||
fi
|
||||
|
||||
# Trigger db init
|
||||
echo "Running DB init..."
|
||||
php -c /usr/local/etc/php -f /web/inc/init_db.inc.php
|
||||
|
@ -10,7 +10,7 @@ while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${D
|
||||
sleep 2
|
||||
done
|
||||
|
||||
until dig +short mailcow.email @unbound > /dev/null; do
|
||||
until dig +short mailcow.email > /dev/null; do
|
||||
echo "Waiting for DNS..."
|
||||
sleep 1
|
||||
done
|
||||
|
@ -28,7 +28,7 @@ destination d_redis_f2b_channel {
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
filter f_mail { facility(mail); };
|
||||
|
@ -28,7 +28,7 @@ destination d_redis_f2b_channel {
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
filter f_mail { facility(mail); };
|
||||
|
@ -4,14 +4,13 @@ LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/
|
||||
ENV LC_ALL C
|
||||
ENV GOSU_VERSION 1.11
|
||||
ENV GOSU_VERSION 1.12
|
||||
|
||||
# Prerequisites
|
||||
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
cron \
|
||||
gettext \
|
||||
gnupg \
|
||||
mariadb-client \
|
||||
|
@ -249,14 +249,4 @@ rsync -a /usr/lib/GNUstep/SOGo/. /sogo_web/
|
||||
# Chown backup path
|
||||
chown -R sogo:sogo /sogo_backup
|
||||
|
||||
# Creating cronjobs
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "* * * * * sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/sieve.creds 2>/dev/null" > /etc/cron.d/sogo
|
||||
echo "* * * * * sogo /usr/sbin/sogo-tool expire-sessions ${SOGO_EXPIRE_SESSION}" >> /etc/cron.d/sogo
|
||||
echo "0 0 * * * sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds" >> /etc/cron.d/sogo
|
||||
echo "0 2 * * * sogo /usr/sbin/sogo-tool backup /sogo_backup ALL" >> /etc/cron.d/sogo
|
||||
else
|
||||
rm /etc/cron.d/sogo
|
||||
fi
|
||||
|
||||
exec gosu sogo /usr/sbin/sogod
|
||||
|
@ -11,18 +11,13 @@ stderr_logfile_maxbytes=0
|
||||
autostart=true
|
||||
priority=1
|
||||
|
||||
[program:cron]
|
||||
command=/usr/sbin/cron -f
|
||||
autorestart=true
|
||||
priority=2
|
||||
|
||||
[program:bootstrap-sogo]
|
||||
command=/bootstrap-sogo.sh
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
priority=3
|
||||
priority=2
|
||||
startretries=10
|
||||
autorestart=true
|
||||
stopwaitsecs=120
|
||||
|
@ -30,7 +30,7 @@ destination d_redis_f2b_channel {
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
log {
|
||||
|
@ -30,7 +30,7 @@ destination d_redis_f2b_channel {
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
log {
|
||||
|
@ -109,7 +109,7 @@ function mail_error() {
|
||||
SUBJECT="${BODY}"
|
||||
BODY="Please see netfilter-mailcow for more details and triggered rules."
|
||||
else
|
||||
SUBJECT="Watchdog ALERT: ${1}"
|
||||
SUBJECT="${WATCHDOG_SUBJECT}: ${1}"
|
||||
fi
|
||||
IFS=',' read -r -a MAIL_RCPTS <<< "${WATCHDOG_NOTIFY_EMAIL}"
|
||||
for rcpt in "${MAIL_RCPTS[@]}"; do
|
||||
@ -210,7 +210,7 @@ external_checks() {
|
||||
sleep 60
|
||||
else
|
||||
diff_c=0
|
||||
sleep $(( ( RANDOM % 20 ) + 120 ))
|
||||
sleep $(( ( RANDOM % 20 ) + 1800 ))
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
|
@ -3,6 +3,8 @@
|
||||
charset utf-8;
|
||||
override_charset on;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
|
||||
|
@ -1,4 +1,3 @@
|
||||
server_tokens off;
|
||||
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
|
||||
server_names_hash_bucket_size 64;
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
max_execution_time = 3600
|
||||
max_input_time = 3600
|
||||
memory_limit = 512M
|
||||
|
@ -15,7 +15,7 @@ smtpd_relay_restrictions = permit_mynetworks,
|
||||
alias_maps = hash:/etc/aliases
|
||||
alias_database = hash:/etc/aliases
|
||||
relayhost =
|
||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 [fe80::]/10 [fc00::]/7
|
||||
mynetworks_style = subnet
|
||||
mailbox_size_limit = 0
|
||||
recipient_delimiter = +
|
||||
inet_interfaces = all
|
||||
@ -198,6 +198,3 @@ parent_domain_matches_subdomains = debug_peer_list,fast_flush_domains,mynetworks
|
||||
|
||||
# DO NOT EDIT ANYTHING BELOW #
|
||||
# User overrides #
|
||||
|
||||
myhostname = mail.gnous.fr
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/X-EMV-Platform; .*/i
|
||||
/.*nur-1-click*/i
|
||||
/.*nur-1-click.*/i
|
||||
/.*episerver.*/i
|
||||
/.*supergewinne.*/i
|
||||
/List-Unsubscribe.*nbps\.eu/i
|
||||
|
@ -32,4 +32,4 @@ selector_prefix = "DKIM_SELECTORS";
|
||||
# forwards are arc signed, rejects are dkim signed
|
||||
sign_networks = "/etc/rspamd/custom/dovecot_trusted.map";
|
||||
use_domain_sign_networks = "header";
|
||||
sign_headers = "from:sender:reply-to:subject:date:message-id:to:cc:mime-version:content-type:content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:in-reply-to:references:list-id:list-help:list-owner:list-unsubscribe:list-subscribe:list-post:openpgp:autocrypt";
|
||||
sign_headers = "from:sender:reply-to:subject:date:message-id:to:cc:mime-version:content-type:content-transfer-encoding:content-language:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:in-reply-to:references:list-id:list-help:list-owner:list-unsubscribe:list-subscribe:list-post:list-unsubscribe-post:disposition-notification-to:disposition-notification-options:original-recipient:openpgp:autocrypt";
|
||||
|
@ -80,7 +80,6 @@ SIEVE_HOST {
|
||||
type = "ip";
|
||||
map = "${LOCAL_CONFDIR}/custom/dovecot_trusted.map";
|
||||
symbols_set = ["SIEVE_HOST"];
|
||||
score = -15;
|
||||
}
|
||||
|
||||
RSPAMD_HOST {
|
||||
|
@ -3,7 +3,6 @@ rules {
|
||||
selector "ip" {
|
||||
}
|
||||
backend "redis" {
|
||||
servers = "redis";
|
||||
}
|
||||
symbol = "IP_REPUTATION";
|
||||
}
|
||||
|
@ -1,86 +1,36 @@
|
||||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/* EXAMPLE - EXAMPLE - EXAMPLE - EXAMPLE - EXAMPLE - EXAMPLE - EXAMPLE
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common')
|
||||
.config(configure)
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
configure.$inject = ['$mdThemingProvider'];
|
||||
function configure($mdThemingProvider) {
|
||||
|
||||
/**
|
||||
* The SOGo palettes are defined in js/Common/Common.app.js:
|
||||
*
|
||||
* - sogo-green
|
||||
* - sogo-blue
|
||||
* - sogo-grey
|
||||
*
|
||||
* The Material palettes are also available:
|
||||
*
|
||||
* - red
|
||||
* - pink
|
||||
* - purple
|
||||
* - deep-purple
|
||||
* - indigo
|
||||
* - blue
|
||||
* - light-blue
|
||||
* - cyan
|
||||
* - teal
|
||||
* - green
|
||||
* - light-green
|
||||
* - lime
|
||||
* - yellow
|
||||
* - amber
|
||||
* - orange
|
||||
* - deep-orange
|
||||
* - brown
|
||||
* - grey
|
||||
* - blue-grey
|
||||
*
|
||||
* See https://material.angularjs.org/latest/Theming/01_introduction
|
||||
* and https://material.io/archive/guidelines/style/color.html#color-color-palette
|
||||
*
|
||||
* You can also define your own palettes. See js/Common/Common.app.js.
|
||||
*/
|
||||
|
||||
// Create new background palette from grey palette
|
||||
var greyMap = $mdThemingProvider.extendPalette('grey', {
|
||||
// background color of sidebar selected item,
|
||||
// background color of right panel,
|
||||
// background color of menus (autocomplete and contextual menus)
|
||||
'200': 'F5F5F5',
|
||||
// background color of sidebar
|
||||
'300': 'E5E5E5',
|
||||
// background color of the busy periods of the attendees editor
|
||||
'1000': '4C566A'
|
||||
});
|
||||
var greenCow = $mdThemingProvider.extendPalette('green', {
|
||||
'600': 'E5E5E5'
|
||||
});
|
||||
|
||||
$mdThemingProvider.definePalette('frost-grey', greyMap);
|
||||
$mdThemingProvider.definePalette('green-cow', greenCow);
|
||||
|
||||
// Apply new palettes to the default theme, remap some of the hues
|
||||
$mdThemingProvider.theme('default')
|
||||
.primaryPalette('green-cow', {
|
||||
'default': '400', // background color of top toolbars
|
||||
'default': '400',
|
||||
'hue-1': '400',
|
||||
'hue-2': '600', // background color of sidebar toolbar
|
||||
'hue-2': '600',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.accentPalette('green', {
|
||||
'default': '600', // background color of fab buttons
|
||||
'hue-1': '300', // background color of center list toolbar
|
||||
'default': '600',
|
||||
'hue-1': '300',
|
||||
'hue-2': '300',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.backgroundPalette('frost-grey');
|
||||
|
||||
$mdThemingProvider.generateThemesOnDemand(false);
|
||||
}
|
||||
})();
|
||||
*/
|
@ -85,7 +85,7 @@
|
||||
//LDAPDebugEnabled = YES;
|
||||
//PGDebugEnabled = YES;
|
||||
//MySQL4DebugEnabled = YES;
|
||||
SOGoUIxDebugEnabled = YES;
|
||||
//SOGoUIxDebugEnabled = YES;
|
||||
//WODontZipResponse = YES;
|
||||
WOLogFile = "/dev/sogo_log";
|
||||
}
|
||||
|
0
data/hooks/phpfpm/.gitkeep
Normal file
0
data/hooks/phpfpm/.gitkeep
Normal file
0
data/hooks/postfix/.gitkeep
Normal file
0
data/hooks/postfix/.gitkeep
Normal file
0
data/hooks/rspamd/.gitkeep
Normal file
0
data/hooks/rspamd/.gitkeep
Normal file
0
data/hooks/unbound/.gitkeep
Normal file
0
data/hooks/unbound/.gitkeep
Normal file
@ -13,9 +13,18 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
<div class="container">
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#tab-access" aria-controls="tab-access" role="tab" data-toggle="tab"><?=$lang['admin']['access'];?></a></li>
|
||||
<li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['configuration'];?>
|
||||
<span class="caret"></span></a>
|
||||
<li class="dropdown active">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['access'];?><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="active" data-dont-remember="1" role="presentation"><a href="#tab-config-admins" aria-controls="tab-config-admins" role="tab" data-toggle="tab"><?=$lang['admin']['admins'];?></a></li>
|
||||
<!-- <li role="presentation"><a href="#tab-config-ldap-admins" aria-controls="tab-config-ldap-admins" role="tab" data-toggle="tab"><?=$lang['admin']['admins_ldap'];?></a></li> -->
|
||||
<li role="presentation"><a href="#tab-config-oauth2" aria-controls="tab-config-oauth2" role="tab" data-toggle="tab">OAuth2 Apps</a></li>
|
||||
<li role="presentation"><a href="#tab-config-rspamd" aria-controls="tab-config-rspamd" role="tab" data-toggle="tab">Rspamd UI</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['configuration'];?><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li role="presentation"><a href="#tab-config-dkim" aria-controls="tab-config-dkim" role="tab" data-toggle="tab"><?=$lang['admin']['dkim_keys'];?></a></li>
|
||||
<li role="presentation"><a href="#tab-config-fwdhosts" aria-controls="tab-config-fwdhosts" role="tab" data-toggle="tab"><?=$lang['admin']['forwarding_hosts'];?></a></li>
|
||||
@ -23,6 +32,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
<li role="presentation"><a href="#tab-config-quarantine" aria-controls="tab-config-quarantine" role="tab" data-toggle="tab"><?=$lang['admin']['quarantine'];?></a></li>
|
||||
<li role="presentation"><a href="#tab-config-quota" aria-controls="tab-config-quota" role="tab" data-toggle="tab"><?=$lang['admin']['quota_notifications'];?></a></li>
|
||||
<li role="presentation"><a href="#tab-config-rsettings" aria-controls="tab-config-rsettings" role="tab" data-toggle="tab"><?=$lang['admin']['rspamd_settings_map'];?></a></li>
|
||||
<li role="presentation"><a href="#tab-config-password-policy" aria-controls="tab-config-password-policy" role="tab" data-toggle="tab"><?=$lang['admin']['password_policy'];?></a></li>
|
||||
<li role="presentation"><a href="#tab-config-customize" aria-controls="tab-config-customize" role="tab" data-toggle="tab"><?=$lang['admin']['customize'];?></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@ -40,7 +50,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="tab-content" style="padding-top:20px">
|
||||
<div role="tabpanel" class="tab-pane active" id="tab-access">
|
||||
<div role="tabpanel" class="tab-pane active" id="tab-config-admins">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading"><?=$lang['admin']['admin_details'];?></div>
|
||||
<div class="panel-body">
|
||||
@ -77,7 +87,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
foreach ($tfa_data['additional'] as $key_info) {
|
||||
?>
|
||||
<form style="display:inline;" method="post">
|
||||
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
|
||||
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>">
|
||||
<div style="padding:4px;margin:4px" class="label label-keys label-<?=($_SESSION['tfa_id'] == $key_info['id']) ? 'success' : 'default'; ?>">
|
||||
<?=$key_info['key_id'];?>
|
||||
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=$lang['admin']['remove'];?>]</a>
|
||||
@ -128,7 +138,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
</td>
|
||||
<td style="min-width:240px;text-align: right">
|
||||
<form style="display:inline;" method="post">
|
||||
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>" />
|
||||
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>">
|
||||
<div class="btn-group">
|
||||
<a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['fido2']['rename'];?></a>
|
||||
<a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
||||
@ -321,7 +331,17 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-config-ldap-admins">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['admins_ldap'];?></div>
|
||||
<div class="panel-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-config-oauth2">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">OAuth2 Apps</div>
|
||||
<div class="panel-body">
|
||||
@ -345,7 +365,9 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-config-rspamd">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Rspamd UI</h3>
|
||||
@ -381,7 +403,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI" />
|
||||
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -507,7 +529,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||
?>
|
||||
<div class="row collapse in dkim_key_valid">
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>"></div>
|
||||
<div class="col-md-3">
|
||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong>
|
||||
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||
@ -526,7 +548,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
else {
|
||||
?>
|
||||
<div class="row collapse in dkim_key_missing">
|
||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled></div>
|
||||
<div class="col-md-3">
|
||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong><br><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||
</div>
|
||||
@ -541,7 +563,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||
?>
|
||||
<div class="row collapse in dkim_key_valid">
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>"></div>
|
||||
<div class="col-md-2 col-md-offset-1">
|
||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
||||
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||
@ -560,7 +582,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
else {
|
||||
?>
|
||||
<div class="row collapse in dkim_key_missing">
|
||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" disabled /></div>
|
||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" disabled></div>
|
||||
<div class="col-md-2 col-md-offset-1">
|
||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||
</div>
|
||||
@ -577,7 +599,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||
?>
|
||||
<div class="row collapse in dkim_key_unused">
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>"></div>
|
||||
<div class="col-md-3">
|
||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($blind);?></strong>
|
||||
<p class="dkim-label"><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
||||
@ -1212,6 +1234,49 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-config-password-policy">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['password_policy'];?></div>
|
||||
<div class="panel-body">
|
||||
<?php $password_complexity = password_complexity('get'); ?>
|
||||
<form class="form-horizontal" data-id="passwordpolicy" role="form" method="post">
|
||||
<?php
|
||||
foreach ($password_complexity as $name => $value) {
|
||||
if ($name == 'length') {
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="<?=$name;?>"><?=$lang['admin']['password_length'];?>:</label>
|
||||
<div class="col-sm-2">
|
||||
<input type="number" class="form-control" min="3" max="64" name="<?=$name;?>" id="<?=$name;?>" value="<?=$value;?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<input type="hidden" name="<?=$name;?>" value="0">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<label>
|
||||
<input type="checkbox" name="<?=$name;?>" id="<?=$name;?>" value="1" <?=($value == 1) ? 'checked' : null;?>> <?=$lang['admin']["password_policy_$name"];?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-success" data-item="passwordpolicy" data-action="edit_selected" data-id="passwordpolicy" data-api-url='edit/passwordpolicy' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-sys-mails">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['sys_mails'];?></div>
|
||||
@ -1381,7 +1446,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||
?>
|
||||
<hr>
|
||||
<span class="anchor" id="<?=$rspamd_regex_map;?>"></span>
|
||||
<form class="form-horizontal" data-id="<?=$rspamd_regex_map;?>" role="form" method="post">
|
||||
<form class="form-horizontal" data-cached-form="false" data-id="<?=$rspamd_regex_map;?>" role="form" method="post">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3" for="<?=$rspamd_regex_map;?>"><?=$rspamd_regex_desc;?><br><small><?=$rspamd_regex_map;?></small></label>
|
||||
<div class="col-sm-9">
|
||||
|
@ -423,11 +423,11 @@ paths:
|
||||
- domain
|
||||
- active: "1"
|
||||
aliases: "400"
|
||||
restart_sogo: "1"
|
||||
backupmx: "0"
|
||||
defquota: "3072"
|
||||
description: some decsription
|
||||
domain: domain.tld
|
||||
lang: cs
|
||||
mailboxes: "10"
|
||||
maxquota: "10240"
|
||||
quota: "10240"
|
||||
@ -474,13 +474,13 @@ paths:
|
||||
defquota: "3072"
|
||||
description: some decsription
|
||||
domain: domain.tld
|
||||
lang: cs
|
||||
mailboxes: "10"
|
||||
maxquota: "10240"
|
||||
quota: "10240"
|
||||
relay_all_recipients: "0"
|
||||
rl_frame: s
|
||||
rl_value: "10"
|
||||
restart_sogo: "10"
|
||||
properties:
|
||||
active:
|
||||
description: is domain active or not
|
||||
@ -500,23 +500,6 @@ paths:
|
||||
domain:
|
||||
description: Fully qualified domain name
|
||||
type: string
|
||||
lang:
|
||||
description: language code
|
||||
enum:
|
||||
- sk
|
||||
- cs
|
||||
- de
|
||||
- en
|
||||
- es
|
||||
- fr
|
||||
- lv
|
||||
- nl
|
||||
- pl
|
||||
- pt
|
||||
- ru
|
||||
- it
|
||||
- ca
|
||||
type: string
|
||||
mailboxes:
|
||||
description: limit count of mailboxes associated with this domain
|
||||
type: number
|
||||
@ -526,6 +509,9 @@ paths:
|
||||
quota:
|
||||
description: maximum quota for this domain (for all mailboxes in sum)
|
||||
type: number
|
||||
restart_sogo:
|
||||
description: restart SOGo to activate the domain in SOGo
|
||||
type: number
|
||||
relay_all_recipients:
|
||||
description: >-
|
||||
if not, them you have to create "dummy" mailbox for each
|
||||
@ -1021,7 +1007,7 @@ paths:
|
||||
password2:
|
||||
description: mailbox password for confirmation
|
||||
type: string
|
||||
pasword:
|
||||
password:
|
||||
description: mailbox password
|
||||
type: string
|
||||
quota:
|
||||
@ -2811,7 +2797,6 @@ paths:
|
||||
defquota: "3072"
|
||||
description: domain description
|
||||
gal: "1"
|
||||
lang: cs
|
||||
mailboxes: "10"
|
||||
maxquota: "10240"
|
||||
quota: "10240"
|
||||
@ -2841,23 +2826,6 @@ paths:
|
||||
is domain global address list active or not, it enables
|
||||
shared contacts accross domain in SOGo webmail
|
||||
type: boolean
|
||||
lang:
|
||||
description: language code
|
||||
enum:
|
||||
- sk
|
||||
- cs
|
||||
- de
|
||||
- en
|
||||
- es
|
||||
- fr
|
||||
- lv
|
||||
- nl
|
||||
- pl
|
||||
- pt
|
||||
- ru
|
||||
- it
|
||||
- ca
|
||||
type: string
|
||||
mailboxes:
|
||||
description: limit count of mailboxes associated with this domain
|
||||
type: number
|
||||
@ -3052,7 +3020,7 @@ paths:
|
||||
password2:
|
||||
description: new mailbox password for confirmation
|
||||
type: string
|
||||
pasword:
|
||||
password:
|
||||
description: new mailbox password
|
||||
type: string
|
||||
quota:
|
||||
@ -3750,7 +3718,6 @@ paths:
|
||||
description: Some description
|
||||
domain_name: domain.tld
|
||||
gal: "0"
|
||||
lang: en
|
||||
max_new_mailbox_quota: 10737418240
|
||||
max_num_aliases_for_domain: 400
|
||||
max_num_mboxes_for_domain: 10
|
||||
@ -3773,7 +3740,6 @@ paths:
|
||||
description: domain description
|
||||
domain_name: domain2.tld
|
||||
gal: "0"
|
||||
lang: cs
|
||||
max_new_mailbox_quota: 10737418240
|
||||
max_num_aliases_for_domain: 400
|
||||
max_num_mboxes_for_domain: 10
|
||||
|
@ -1 +1 @@
|
||||
div.numberedtextarea-wrapper{position:relative}div.numberedtextarea-wrapper textarea{display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}div.numberedtextarea-line-numbers{position:absolute;top:0;left:0;right:0;bottom:0;width:50px;border-right:none;color:rgba(0,0,0,.4);overflow:hidden}div.numberedtextarea-number{padding-right:6px;text-align:right}
|
||||
div.numberedtextarea-wrapper{position:relative}div.numberedtextarea-wrapper textarea{display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}div.numberedtextarea-line-numbers{position:absolute;top:0;left:0;right:0;bottom:0;width:45px!important;border-right:none;color:rgba(0,0,0,.4);overflow:hidden}div.numberedtextarea-number{padding-right:6px;text-align:right}
|
||||
|
@ -106,13 +106,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="username_new"><?=$lang['edit']['username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" type="text" name="username_new" value="<?=htmlspecialchars($domain_admin);?>" />
|
||||
<input class="form-control" type="text" name="username_new" value="<?=htmlspecialchars($domain_admin);?>" required onkeyup="this.value = this.value.toLowerCase();" />
|
||||
↳ <kbd>a-z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="domains"><?=$lang['edit']['domains'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select data-live-search="true" class="full-width-select" name="domains" multiple required>
|
||||
<select data-live-search="true" data-container="body" class="full-width-select" name="domains" multiple required>
|
||||
<?php
|
||||
foreach ($result['selected_domains'] as $domain):
|
||||
?>
|
||||
@ -167,7 +168,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<div class="form-group">
|
||||
<select id="da_acl" name="da_acl" size="10" multiple>
|
||||
<select id="da_acl" name="da_acl" size="10" data-container="body" multiple>
|
||||
<?php
|
||||
$da_acls = acl('get', 'domainadmin', $domain_admin);
|
||||
foreach ($da_acls as $acl => $val):
|
||||
@ -197,14 +198,15 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
$result = admin('details', $admin);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4><?=$lang['edit']['domain_admin'];?></h4>
|
||||
<h4><?=$lang['edit']['admin'];?></h4>
|
||||
<br>
|
||||
<form class="form-horizontal" data-id="editadmin" role="form" method="post" autocomplete="off">
|
||||
<input type="hidden" value="0" name="active">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="username_new"><?=$lang['edit']['username'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" type="text" name="username_new" value="<?=htmlspecialchars($admin);?>" />
|
||||
<input class="form-control" type="text" name="username_new" onkeyup="this.value = this.value.toLowerCase();" required value="<?=htmlspecialchars($admin);?>" />
|
||||
↳ <kbd>a-z - _ .</kbd>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -15,6 +15,12 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
|
||||
else {
|
||||
$mail_from = "relay@example.org";
|
||||
}
|
||||
if (isset($_GET['mail_rcpt']) && filter_var($_GET['mail_rcpt'], FILTER_VALIDATE_EMAIL)) {
|
||||
$mail_rcpt = $_GET['mail_rcpt'];
|
||||
}
|
||||
else {
|
||||
$mail_rcpt = "null@hosted.mailcow.de";
|
||||
}
|
||||
if ($transport_type == 'transport-map') {
|
||||
$transport_details = transport('details', $transport_id);
|
||||
$nexthop = $transport_details['nexthop'];
|
||||
@ -130,7 +136,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
|
||||
$mail->Port = $port;
|
||||
$mail->setFrom($mail_from, 'Mailer');
|
||||
$mail->Subject = 'A subject for a SMTP test';
|
||||
$mail->addAddress($RELAY_TO, 'Joe Null');
|
||||
$mail->addAddress($mail_rcpt, 'Joe Null');
|
||||
$mail->Body = 'This is our test body';
|
||||
$mail->send();
|
||||
}
|
||||
|
@ -48,40 +48,23 @@ function admin($_action, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$password_hashed = hash_password($password);
|
||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||
VALUES (:username, :password_hashed, '1', :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':password_hashed' => $password_hashed,
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_empty'
|
||||
);
|
||||
if (password_check($password, $password2) !== true) {
|
||||
return false;
|
||||
}
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password_new;
|
||||
}
|
||||
else {
|
||||
$password_hashed = hash_password($password_new);
|
||||
}
|
||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||
VALUES (:username, :password_hashed, '1', :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':password_hashed' => $password_hashed,
|
||||
':active' => $active
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
@ -144,24 +127,17 @@ function admin($_action, $_data = null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
continue;
|
||||
if (!empty($password)) {
|
||||
if (password_check($password, $password2) !== true) {
|
||||
return false;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
continue;
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password;
|
||||
}
|
||||
else {
|
||||
$password_hashed = hash_password($password);
|
||||
}
|
||||
$password_hashed = hash_password($password);
|
||||
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':password_hashed' => $password_hashed,
|
||||
|
@ -23,9 +23,9 @@ function app_passwd($_action, $_data = null) {
|
||||
}
|
||||
switch ($_action) {
|
||||
case 'add':
|
||||
$app_name = trim($_data['app_name']);
|
||||
$password = $_data['app_passwd'];
|
||||
$password2 = $_data['app_passwd2'];
|
||||
$app_name = htmlspecialchars(trim($_data['app_name']));
|
||||
$password = $_data['app_passwd'];
|
||||
$password2 = $_data['app_passwd2'];
|
||||
$active = intval($_data['active']);
|
||||
$domain = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||
if (empty($domain)) {
|
||||
@ -94,7 +94,7 @@ function app_passwd($_action, $_data = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$app_name = trim($app_name);
|
||||
$app_name = htmlspecialchars(trim($app_name));
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
@ -198,6 +198,7 @@ function app_passwd($_action, $_data = null) {
|
||||
$app_passwd_data = array();
|
||||
return false;
|
||||
}
|
||||
$app_passwd_data['name'] = htmlspecialchars(trim($app_passwd_data['name']));
|
||||
return $app_passwd_data;
|
||||
break;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
continue;
|
||||
@ -29,7 +29,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
continue;
|
||||
@ -37,7 +37,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
continue;
|
||||
@ -62,7 +62,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
@ -76,7 +76,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
@ -84,14 +84,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_added', $domain)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
continue;
|
||||
@ -102,7 +102,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
@ -112,7 +112,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (empty($from_domain_dkim)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $from_domain)
|
||||
);
|
||||
continue;
|
||||
@ -128,14 +128,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_duplicated', $from_domain, $to_domain)
|
||||
);
|
||||
}
|
||||
@ -144,7 +144,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
@ -156,7 +156,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($ssl_error = openssl_error_string()) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('private_key_error', $ssl_error)
|
||||
);
|
||||
return false;
|
||||
@ -173,7 +173,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (!is_valid_domain_name($domain)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
return false;
|
||||
@ -182,7 +182,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($overwrite_existing == 0) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_exists', $domain)
|
||||
);
|
||||
return false;
|
||||
@ -191,7 +191,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (!ctype_alnum($dkim_selector)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
return false;
|
||||
@ -205,7 +205,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
@ -218,14 +218,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_added', $domain)
|
||||
);
|
||||
return true;
|
||||
@ -270,7 +270,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
@ -286,7 +286,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
@ -295,7 +295,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
if (!is_valid_domain_name($domain)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||
);
|
||||
continue;
|
||||
@ -309,14 +309,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('dkim_removed', htmlspecialchars($domain))
|
||||
);
|
||||
}
|
||||
|
@ -65,61 +65,44 @@ function domain_admin($_action, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$password_hashed = hash_password($password);
|
||||
$valid_domains = 0;
|
||||
foreach ($domains as $domain) {
|
||||
if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('domain_invalid', htmlspecialchars($domain))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$valid_domains++;
|
||||
$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
|
||||
VALUES (:username, :domain, :created, :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':domain' => $domain,
|
||||
':created' => date('Y-m-d H:i:s'),
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
if ($valid_domains != 0) {
|
||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||
VALUES (:username, :password_hashed, '0', :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':password_hashed' => $password_hashed,
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
if (password_check($password, $password2) !== true) {
|
||||
continue;
|
||||
}
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password;
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_empty'
|
||||
);
|
||||
return false;
|
||||
$password_hashed = hash_password($password);
|
||||
}
|
||||
$valid_domains = 0;
|
||||
foreach ($domains as $domain) {
|
||||
if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('domain_invalid', htmlspecialchars($domain))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$valid_domains++;
|
||||
$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
|
||||
VALUES (:username, :domain, :created, :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':domain' => $domain,
|
||||
':created' => date('Y-m-d H:i:s'),
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
if ($valid_domains != 0) {
|
||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||
VALUES (:username, :password_hashed, '0', :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':password_hashed' => $password_hashed,
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
$stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)");
|
||||
$stmt->execute(array(
|
||||
@ -218,24 +201,17 @@ function domain_admin($_action, $_data = null) {
|
||||
));
|
||||
}
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
continue;
|
||||
if (!empty($password)) {
|
||||
if (password_check($password, $password2) !== true) {
|
||||
return false;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
continue;
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password;
|
||||
}
|
||||
else {
|
||||
$password_hashed = hash_password($password);
|
||||
}
|
||||
$password_hashed = hash_password($password);
|
||||
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':password_hashed' => $password_hashed,
|
||||
@ -296,30 +272,15 @@ function domain_admin($_action, $_data = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!empty($password_new2) && !empty($password_new)) {
|
||||
if ($password_new2 != $password_new) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$password_hashed = hash_password($password_new);
|
||||
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':password_hashed' => $password_hashed,
|
||||
':username' => $username
|
||||
));
|
||||
if (password_check($password_new, $password_new2) !== true) {
|
||||
return false;
|
||||
}
|
||||
$password_hashed = hash_password($password_new);
|
||||
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':password_hashed' => $password_hashed,
|
||||
':username' => $username
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
|
@ -133,14 +133,6 @@ function fail2ban($_action, $_data = null) {
|
||||
$redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => print_r($_data, true)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
|
@ -88,26 +88,158 @@ function hash_password($password) {
|
||||
// in case default pass scheme is not defined, falling back to BLF-CRYPT.
|
||||
global $default_pass_scheme;
|
||||
$pw_hash = NULL;
|
||||
switch (strtoupper($default_pass_scheme)) {
|
||||
case "SSHA":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA}".base64_encode(hash('sha1', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "SSHA256":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "SSHA512":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA512}".base64_encode(hash('sha512', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "BLF-CRYPT":
|
||||
default:
|
||||
$pw_hash = "{BLF-CRYPT}" . password_hash($password, PASSWORD_BCRYPT);
|
||||
break;
|
||||
// support pre-hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$pw_hash = $password;
|
||||
}
|
||||
else {
|
||||
switch (strtoupper($default_pass_scheme)) {
|
||||
case "SSHA":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA}".base64_encode(hash('sha1', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "SSHA256":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "SSHA512":
|
||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||
$pw_hash = "{SSHA512}".base64_encode(hash('sha512', $password . $salt_str, true) . $salt_str);
|
||||
break;
|
||||
case "BLF-CRYPT":
|
||||
default:
|
||||
$pw_hash = "{BLF-CRYPT}" . password_hash($password, PASSWORD_BCRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $pw_hash;
|
||||
}
|
||||
function password_complexity($_action, $_data = null) {
|
||||
global $redis;
|
||||
global $lang;
|
||||
switch ($_action) {
|
||||
case 'edit':
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$is_now = password_complexity('get');
|
||||
if (!empty($is_now)) {
|
||||
$length = (isset($_data['length']) && intval($_data['length']) >= 3) ? intval($_data['length']) : $is_now['length'];
|
||||
$chars = (isset($_data['chars'])) ? intval($_data['chars']) : $is_now['chars'];
|
||||
$lowerupper = (isset($_data['lowerupper'])) ? intval($_data['lowerupper']) : $is_now['lowerupper'];
|
||||
$special_chars = (isset($_data['special_chars'])) ? intval($_data['special_chars']) : $is_now['special_chars'];
|
||||
$numbers = (isset($_data['numbers'])) ? intval($_data['numbers']) : $is_now['numbers'];
|
||||
}
|
||||
try {
|
||||
$redis->hMSet('PASSWD_POLICY', [
|
||||
'length' => $length,
|
||||
'chars' => $chars,
|
||||
'special_chars' => $special_chars,
|
||||
'lowerupper' => $lowerupper,
|
||||
'numbers' => $numbers
|
||||
]);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => 'password_policy_saved'
|
||||
);
|
||||
break;
|
||||
case 'get':
|
||||
try {
|
||||
$length = $redis->hGet('PASSWD_POLICY', 'length');
|
||||
$chars = $redis->hGet('PASSWD_POLICY', 'chars');
|
||||
$special_chars = $redis->hGet('PASSWD_POLICY', 'special_chars');
|
||||
$lowerupper = $redis->hGet('PASSWD_POLICY', 'lowerupper');
|
||||
$numbers = $redis->hGet('PASSWD_POLICY', 'numbers');
|
||||
return array(
|
||||
'length' => $length,
|
||||
'chars' => $chars,
|
||||
'special_chars' => $special_chars,
|
||||
'lowerupper' => $lowerupper,
|
||||
'numbers' => $numbers
|
||||
);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case 'html':
|
||||
$policies = password_complexity('get');
|
||||
foreach ($policies as $name => $value) {
|
||||
if ($value != 0) {
|
||||
$policy_text[] = sprintf($lang['admin']["password_policy_$name"], $value);
|
||||
}
|
||||
}
|
||||
return '<p class="help-block small">- ' . implode('<br>- ', $policy_text) . '</p>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
function password_check($password1, $password2) {
|
||||
$password_complexity = password_complexity('get');
|
||||
|
||||
if (empty($password1) || empty($password2)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($password1 != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$given_password['length'] = strlen($password1);
|
||||
$given_password['special_chars'] = preg_match('/[^a-zA-Z\d]/', $password1);
|
||||
$given_password['chars'] = preg_match('/[a-zA-Z]/',$password1);
|
||||
$given_password['numbers'] = preg_match('/\d/', $password1);
|
||||
$lower = strlen(preg_replace("/[^a-z]/", '', $password1));
|
||||
$upper = strlen(preg_replace("/[^A-Z]/", '', $password1));
|
||||
$given_password['lowerupper'] = ($lower > 0 && $upper > 0) ? true : false;
|
||||
|
||||
if (
|
||||
($given_password['length'] < $password_complexity['length']) ||
|
||||
($password_complexity['special_chars'] == 1 && (intval($given_password['special_chars']) != $password_complexity['special_chars'])) ||
|
||||
($password_complexity['chars'] == 1 && (intval($given_password['chars']) != $password_complexity['chars'])) ||
|
||||
($password_complexity['numbers'] == 1 && (intval($given_password['numbers']) != $password_complexity['numbers'])) ||
|
||||
($password_complexity['lowerupper'] == 1 && (intval($given_password['lowerupper']) != $password_complexity['lowerupper']))
|
||||
) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
function last_login($user) {
|
||||
global $pdo;
|
||||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||
|
@ -997,7 +997,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
COUNT(*) as count,
|
||||
COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
|
||||
FROM `mailbox`
|
||||
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||
WHERE (`kind` = '' OR `kind` = NULL)
|
||||
AND `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $domain));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
@ -1045,38 +1045,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password;
|
||||
}
|
||||
else {
|
||||
$password_hashed = hash_password($password);
|
||||
}
|
||||
if (password_check($password, $password2) !== true) {
|
||||
return false;
|
||||
}
|
||||
// support pre hashed passwords
|
||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||
$password_hashed = $password;
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'password_empty'
|
||||
);
|
||||
return false;
|
||||
$password_hashed = hash_password($password);
|
||||
}
|
||||
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
|
||||
$_SESSION['return'][] = array(
|
||||
@ -1940,6 +1917,52 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if ($_data['expand_alias'] === true || $_data['expand_alias'] == 1) {
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
|
||||
WHERE `address` = :address
|
||||
AND `domain` NOT IN (
|
||||
SELECT `alias_domain` FROM `alias_domain`
|
||||
)");
|
||||
$stmt->execute(array(
|
||||
':address' => $address,
|
||||
));
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
if ($num_results == 0) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'warning',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('is_not_primary_alias', htmlspecialchars($address))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `goto`, GROUP_CONCAT(CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`)) AS `missing_alias`
|
||||
FROM `alias` JOIN `alias_domain` ON `alias_domain`.`target_domain` = `alias`.`domain`
|
||||
WHERE CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`) NOT IN (
|
||||
SELECT `address` FROM `alias` WHERE `address` != `goto`
|
||||
)
|
||||
AND `alias`.`address` NOT IN (
|
||||
SELECT `address` FROM `alias` WHERE `address` = `goto`
|
||||
)
|
||||
AND `address` = :address ;");
|
||||
$stmt->execute(array(
|
||||
':address' => $address
|
||||
));
|
||||
$missing_aliases = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($missing_aliases['missing_alias'])) {
|
||||
mailbox('add', 'alias', array(
|
||||
'address' => $missing_aliases['missing_alias'],
|
||||
'goto' => $missing_aliases['goto'],
|
||||
'sogo_visible' => 1,
|
||||
'active' => 1
|
||||
));
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('alias_modified', htmlspecialchars($address))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
|
||||
if ($is_now['address'] != $address) {
|
||||
$local_part = strstr($address, '@', true);
|
||||
@ -2175,7 +2198,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
|
||||
COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
|
||||
FROM `mailbox`
|
||||
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||
WHERE (`kind` = '' OR `kind` = NULL)
|
||||
AND domain = :domain");
|
||||
$stmt->execute(array(':domain' => $domain));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
@ -2348,11 +2371,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `quota`, `maxquota`
|
||||
FROM `domain`
|
||||
WHERE `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $domain));
|
||||
$DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
@ -2361,7 +2379,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if ((($is_now['quota_used'] / 1048576) + $quota_m) > $DomainData['quota']) {
|
||||
$DomainData = mailbox('get', 'domain_details', $domain);
|
||||
if ($quota_m > ($is_now['max_new_quota'] / 1048576)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
@ -2369,11 +2388,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if ($quota_m > $DomainData['maxquota']) {
|
||||
if ($quota_m > $DomainData['max_quota_for_mbox']) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota'])
|
||||
'msg' => array('mailbox_quota_exceeded', $DomainData['max_quota_for_mbox'])
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -2563,21 +2582,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
));
|
||||
}
|
||||
}
|
||||
if (!empty($password) && !empty($password2)) {
|
||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'password_complexity'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if ($password != $password2) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'password_mismatch'
|
||||
);
|
||||
if (!empty($password)) {
|
||||
if (password_check($password, $password2) !== true) {
|
||||
continue;
|
||||
}
|
||||
// support pre hashed passwords
|
||||
@ -2847,7 +2853,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` = :domain");
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => $_data,
|
||||
));
|
||||
@ -2857,7 +2863,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND (`domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role)");
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND (`domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role)");
|
||||
$stmt->execute(array(
|
||||
':username' => $_SESSION['mailcow_cc_username'],
|
||||
':role' => $_SESSION['mailcow_cc_role'],
|
||||
@ -3392,10 +3398,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
if (empty($row)) {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) AS `count`,
|
||||
$stmt = $pdo->prepare("SELECT COUNT(`username`) AS `count`,
|
||||
COALESCE(SUM(`quota`), 0) AS `in_use`
|
||||
FROM `mailbox`
|
||||
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||
WHERE (`kind` = '' OR `kind` = NULL)
|
||||
AND `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$MailboxDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
@ -3451,7 +3457,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
|
||||
$domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
|
||||
$domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) AS `alias_count` FROM `alias`
|
||||
$stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
|
||||
WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
|
||||
AND `address` NOT IN (
|
||||
SELECT `username` FROM `mailbox`
|
||||
@ -3479,7 +3485,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
$mailboxdata = array();
|
||||
$rl = ratelimit('get', 'mailbox', $_data);
|
||||
$last_imap_login = $redis->Get('last-login/imap/' . $_data);
|
||||
$last_smtp_login = $redis->Get('last-login/smtp/' . $_data);
|
||||
$last_pop3_login = $redis->Get('last-login/pop3/' . $_data);
|
||||
@ -3507,7 +3512,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`attributes`,
|
||||
`quota2`.`messages`
|
||||
FROM `mailbox`, `quota2`, `domain`
|
||||
WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' AND `mailbox`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
|
||||
WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
|
||||
AND `mailbox`.`username` = `quota2`.`username`
|
||||
AND `domain`.`domain` = `mailbox`.`domain`
|
||||
AND `mailbox`.`username` = :mailbox");
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
@ -3524,55 +3532,34 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`attributes`,
|
||||
`quota2replica`.`messages`
|
||||
FROM `mailbox`, `quota2replica`, `domain`
|
||||
WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' AND `mailbox`.`username` = `quota2replica`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
|
||||
WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
|
||||
AND `mailbox`.`username` = `quota2replica`.`username`
|
||||
AND `domain`.`domain` = `mailbox`.`domain`
|
||||
AND `mailbox`.`username` = :mailbox");
|
||||
}
|
||||
$stmt->execute(array(
|
||||
':mailbox' => $_data,
|
||||
));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
|
||||
$stmt->execute(array(':username' => $_data));
|
||||
$PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` = :domain AND `username` != :username");
|
||||
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
|
||||
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
|
||||
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
||||
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
||||
if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
|
||||
}
|
||||
|
||||
$mailboxdata['username'] = $row['username'];
|
||||
if (!empty($rl)) {
|
||||
$mailboxdata['rl'] = $rl;
|
||||
$mailboxdata['rl_scope'] = 'mailbox';
|
||||
}
|
||||
else {
|
||||
$mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
|
||||
$mailboxdata['rl_scope'] = 'domain';
|
||||
}
|
||||
$mailboxdata['is_relayed'] = $row['backupmx'];
|
||||
$mailboxdata['name'] = $row['name'];
|
||||
$mailboxdata['last_imap_login'] = $last_imap_login;
|
||||
$mailboxdata['last_smtp_login'] = $last_smtp_login;
|
||||
$mailboxdata['last_pop3_login'] = $last_pop3_login;
|
||||
$mailboxdata['active'] = $row['active'];
|
||||
$mailboxdata['active_int'] = $row['active'];
|
||||
$mailboxdata['domain'] = $row['domain'];
|
||||
$mailboxdata['domain_xmpp'] = $row['domain_xmpp'];
|
||||
$mailboxdata['name'] = $row['name'];
|
||||
$mailboxdata['domain_xmpp_prefix'] = $row['domain_xmpp_prefix'];
|
||||
$mailboxdata['local_part'] = $row['local_part'];
|
||||
$mailboxdata['quota'] = $row['quota'];
|
||||
$mailboxdata['messages'] = $row['messages'];
|
||||
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
|
||||
$mailboxdata['quota_used'] = intval($row['bytes']);
|
||||
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||
$mailboxdata['messages'] = $row['messages'];
|
||||
$mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
|
||||
$mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
|
||||
|
||||
$mailboxdata['last_imap_login'] = $last_imap_login;
|
||||
$mailboxdata['last_smtp_login'] = $last_smtp_login;
|
||||
$mailboxdata['last_pop3_login'] = $last_pop3_login;
|
||||
|
||||
if ($mailboxdata['percent_in_use'] === '- ') {
|
||||
$mailboxdata['percent_class'] = "info";
|
||||
}
|
||||
@ -3585,6 +3572,38 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
else {
|
||||
$mailboxdata['percent_class'] = "success";
|
||||
}
|
||||
|
||||
if (!isset($_extra) || $_extra != 'reduced') {
|
||||
$rl = ratelimit('get', 'mailbox', $_data);
|
||||
$stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
|
||||
$stmt->execute(array(':username' => $_data));
|
||||
$PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
|
||||
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
|
||||
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
|
||||
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
||||
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
||||
$mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
|
||||
$mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
|
||||
if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
|
||||
}
|
||||
if (!empty($rl)) {
|
||||
$mailboxdata['rl'] = $rl;
|
||||
$mailboxdata['rl_scope'] = 'mailbox';
|
||||
}
|
||||
else {
|
||||
$mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
|
||||
$mailboxdata['rl_scope'] = 'domain';
|
||||
}
|
||||
$mailboxdata['is_relayed'] = $row['backupmx'];
|
||||
}
|
||||
|
||||
return $mailboxdata;
|
||||
break;
|
||||
case 'resource_details':
|
||||
|
@ -137,7 +137,7 @@ function rspamd_maps($_action, $_data = null) {
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'log' => array(__FUNCTION__, $_action, '-'),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
@ -148,7 +148,7 @@ function rspamd_maps($_action, $_data = null) {
|
||||
if (!in_array($map, $rspamd_map_type)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'log' => array(__FUNCTION__, $_action, '-'),
|
||||
'msg' => array('global_map_invalid', $map)
|
||||
);
|
||||
continue;
|
||||
@ -170,14 +170,14 @@ function rspamd_maps($_action, $_data = null) {
|
||||
catch (Exception $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'log' => array(__FUNCTION__, $_action, '-'),
|
||||
'msg' => array('global_map_write_error', htmlspecialchars($map), htmlspecialchars($e->getMessage()))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'log' => array(__FUNCTION__, $_action, '-'),
|
||||
'msg' => array('object_modified', htmlspecialchars($map))
|
||||
);
|
||||
}
|
||||
|
@ -183,6 +183,8 @@ server {
|
||||
include /etc/nginx/conf.d/listen_ssl.active;
|
||||
include /etc/nginx/conf.d/listen_plain.active;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||
|
||||
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "08022021_1000";
|
||||
$db_version = "09032021_1000";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@ -321,7 +321,8 @@ function init_db_schema() {
|
||||
"" => array("username")
|
||||
),
|
||||
"key" => array(
|
||||
"domain" => array("domain")
|
||||
"domain" => array("domain"),
|
||||
"kind" => array("kind")
|
||||
)
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
|
BIN
data/web/inc/lib/WebAuthn/rootCertificates/bsi.pem
Normal file
BIN
data/web/inc/lib/WebAuthn/rootCertificates/bsi.pem
Normal file
Binary file not shown.
@ -8,6 +8,7 @@
|
||||
"ddeboer/imap": "^1.5",
|
||||
"matthiasmullie/minify": "^1.3",
|
||||
"bshaffer/oauth2-server-php": "^1.11",
|
||||
"mustangostang/spyc": "^0.6.3"
|
||||
"mustangostang/spyc": "^0.6.3",
|
||||
"directorytree/ldaprecord": "^2.4"
|
||||
}
|
||||
}
|
||||
|
909
data/web/inc/lib/composer.lock
generated
909
data/web/inc/lib/composer.lock
generated
File diff suppressed because it is too large
Load Diff
2
data/web/inc/lib/vendor/adldap2/adldap2/.gitattributes
vendored
Normal file
2
data/web/inc/lib/vendor/adldap2/adldap2/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
examples/ export-ignore
|
||||
tests/ export-ignore
|
10
data/web/inc/lib/vendor/adldap2/adldap2/.github/issue_template.md
vendored
Normal file
10
data/web/inc/lib/vendor/adldap2/adldap2/.github/issue_template.md
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
- Adldap2 Version: #.#
|
||||
- LDAP Type: <!-- Active Directory / OpenLDAP / FreeIPA / Sun Directory Server? -->
|
||||
- PHP Version: #.#
|
||||
|
||||
<!-- **ISSUES WITHOUT THE ABOVE INFORMATION WILL BE CLOSED!** -->
|
||||
|
||||
### Description:
|
||||
|
||||
|
||||
### Steps To Reproduce:
|
3
data/web/inc/lib/vendor/adldap2/adldap2/.gitignore
vendored
Normal file
3
data/web/inc/lib/vendor/adldap2/adldap2/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/.idea
|
||||
/vendor
|
||||
composer.lock
|
10
data/web/inc/lib/vendor/adldap2/adldap2/.scrutinizer.yml
vendored
Normal file
10
data/web/inc/lib/vendor/adldap2/adldap2/.scrutinizer.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
filter:
|
||||
excluded_paths:
|
||||
- tests/*
|
||||
- src/Schemas/*
|
||||
build:
|
||||
nodes:
|
||||
analysis:
|
||||
tests:
|
||||
override:
|
||||
- command: php-scrutinizer-run
|
7
data/web/inc/lib/vendor/adldap2/adldap2/.styleci.yml
vendored
Normal file
7
data/web/inc/lib/vendor/adldap2/adldap2/.styleci.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
preset: recommended
|
||||
|
||||
enabled:
|
||||
- length_ordered_imports
|
||||
|
||||
disabled:
|
||||
- alpha_ordered_imports
|
19
data/web/inc/lib/vendor/adldap2/adldap2/.travis.yml
vendored
Normal file
19
data/web/inc/lib/vendor/adldap2/adldap2/.travis.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4
|
||||
|
||||
before_script:
|
||||
- travis_retry composer self-update
|
||||
- travis_retry composer install --prefer-source --no-interaction
|
||||
|
||||
script: ./vendor/bin/phpunit
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- v9.0
|
||||
- v8.0
|
57
data/web/inc/lib/vendor/adldap2/adldap2/composer.json
vendored
Normal file
57
data/web/inc/lib/vendor/adldap2/adldap2/composer.json
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "adldap2/adldap2",
|
||||
"type": "library",
|
||||
"description": "A PHP LDAP Package for humans.",
|
||||
"keywords": [
|
||||
"active directory",
|
||||
"directory",
|
||||
"ad",
|
||||
"ldap",
|
||||
"windows",
|
||||
"adldap",
|
||||
"adldap2"
|
||||
],
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"docs": "https://github.com/Adldap2/Adldap2/blob/master/readme.md",
|
||||
"issues": "https://github.com/Adldap2/Adldap2/issues",
|
||||
"source": "https://github.com/Adldap2/Adldap2",
|
||||
"email": "steven_bauman@outlook.com"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Steve Bauman",
|
||||
"email": "steven_bauman@outlook.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"ext-ldap": "*",
|
||||
"ext-json": "*",
|
||||
"psr/log": "~1.0",
|
||||
"psr/simple-cache": "~1.0",
|
||||
"tightenco/collect": "~5.0|~6.0|~7.0|~8.0",
|
||||
"illuminate/contracts": "~5.0|~6.0|~7.0|~8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.0|~7.0|~8.0",
|
||||
"mockery/mockery": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-fileinfo": "fileinfo is required when retrieving user encoded thumbnails"
|
||||
},
|
||||
"archive": {
|
||||
"exclude": ["/examples", "/tests"]
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Adldap\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Adldap\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
0
data/web/inc/lib/vendor/adldap2/adldap2/docs/.nojekyll
vendored
Normal file
0
data/web/inc/lib/vendor/adldap2/adldap2/docs/.nojekyll
vendored
Normal file
16
data/web/inc/lib/vendor/adldap2/adldap2/docs/_coverpage.md
vendored
Normal file
16
data/web/inc/lib/vendor/adldap2/adldap2/docs/_coverpage.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- _coverpage.md -->
|
||||
|
||||
# Adldap2
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/Adldap2/Adldap2"><img src="https://img.shields.io/travis/Adldap2/Adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://scrutinizer-ci.com/g/Adldap2/Adldap2/?branch=master"><img src="https://img.shields.io/scrutinizer/g/adLDAP2/adLDAP2/master.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/dt/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/v/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/l/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
</p>
|
||||
|
||||
> Working with LDAP doesn't need to be hard.
|
||||
|
||||
<!-- background image -->
|
||||

|
27
data/web/inc/lib/vendor/adldap2/adldap2/docs/_sidebar.md
vendored
Normal file
27
data/web/inc/lib/vendor/adldap2/adldap2/docs/_sidebar.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- _sidebar.md -->
|
||||
|
||||
* Getting Started
|
||||
|
||||
* [Introduction](/)
|
||||
* [Installation](installation.md)
|
||||
* [Setup](setup.md)
|
||||
|
||||
* Usage
|
||||
|
||||
* [Searching](searching.md)
|
||||
* [Creating & Updating](models/model.md)
|
||||
* [Events](events.md)
|
||||
* [Logging](logging.md)
|
||||
* [Working With Distiguished Names](distinguished-names.md)
|
||||
* [Troubleshooting](troubleshooting.md)
|
||||
|
||||
* Models
|
||||
* [Model (Base)](models/model.md)
|
||||
* [Computer](models/computer.md)
|
||||
* [Contact](models/contact.md)
|
||||
* [Container](models/container.md)
|
||||
* [Group](models/group.md)
|
||||
* [Organizational Unit](models/ou.md)
|
||||
* [Printer](models/printer.md)
|
||||
* [RootDse](models/root-dse.md)
|
||||
* [User](models/user.md)
|
167
data/web/inc/lib/vendor/adldap2/adldap2/docs/distinguished-names.md
vendored
Normal file
167
data/web/inc/lib/vendor/adldap2/adldap2/docs/distinguished-names.md
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
## Working With Distinguished Names
|
||||
|
||||
Working with DN strings are a pain, but they're about to get easier. Adldap includes a DN builder for easily modifying and
|
||||
creating DN strings.
|
||||
|
||||
> **Note**: All values inserted into DN methods are escaped. You do not need to escape **any** values before hand.
|
||||
|
||||
#### Creating a New DN
|
||||
|
||||
To create a new DN, construct a new `Adldap\Models\Attributes\DistinguishedName` instance:
|
||||
|
||||
```php
|
||||
$dn = new Adldap\Models\Attributes\DistinguishedName();
|
||||
```
|
||||
|
||||
You can also pass in a current DN string and start modifying it:
|
||||
|
||||
```php
|
||||
$currentDn = 'cn=John Doe,ou=Accounting,dc=corp,dc=acme,dc=org';
|
||||
|
||||
$dn = new Adldap\Models\Attributes\DistinguishedName($currentDn);
|
||||
```
|
||||
|
||||
#### Adding / Removing a Domain Component
|
||||
|
||||
```php
|
||||
// Add Domain Component
|
||||
$dn->addDc('corp');
|
||||
|
||||
// Remove Domain Component
|
||||
$dn->removeDc('corp');
|
||||
```
|
||||
|
||||
#### Adding / Removing an Organizational Unit
|
||||
|
||||
```php
|
||||
// Add Organizational Unit
|
||||
$dn->addOu('Accounting');
|
||||
|
||||
// Remove Organizational Unit
|
||||
$dn->removeOu('Accounting');
|
||||
```
|
||||
|
||||
#### Adding / Removing Common Names
|
||||
|
||||
```php
|
||||
// Add Common Name
|
||||
$dn->addCn('John Doe');
|
||||
|
||||
// Remove Common Name
|
||||
$dn->removeCn('John Doe');
|
||||
```
|
||||
|
||||
#### Setting a base
|
||||
|
||||
If you'd like to set the base DN, such as a domain component RDN, use the `setBase()` method:
|
||||
|
||||
```php
|
||||
$base = 'dc=corp,dc=acme,dc=org';
|
||||
|
||||
$dn->setBase($base);
|
||||
```
|
||||
|
||||
#### Creating a DN From A Model
|
||||
|
||||
When you're creating a new LDAP record, you'll need to create a distinguished name as well. Let's go through an example of
|
||||
creating a new user.
|
||||
|
||||
```php
|
||||
$user = $provider->make()->user();
|
||||
|
||||
$user->setCommonName('John Doe');
|
||||
$user->setFirstName('John');
|
||||
$user->setLastName('Doe');
|
||||
```
|
||||
|
||||
So we've set the basic information on the user, but we run into trouble when we want to put the user into a certain container
|
||||
(such as 'Accounting') which is done through the DN. Let's go through this example:
|
||||
|
||||
```php
|
||||
$dn = $user->getDnBuilder();
|
||||
|
||||
$dn->addCn($user->getCommonName());
|
||||
$dn->addOu('Accounting');
|
||||
$dn->addDc('corp');
|
||||
$dn->addDc('acme');
|
||||
$dn->addDc('org');
|
||||
|
||||
// Returns 'cn=John Doe,ou=Accounting,dc=corp,dc=acme,dc=org'
|
||||
echo $dn->get();
|
||||
|
||||
// The DistinguishedName object also contains the __toString() magic method
|
||||
// so you can also just echo the object itself
|
||||
echo $dn;
|
||||
```
|
||||
|
||||
Now we've built a DN, and all we have to do is set it on the new user:
|
||||
|
||||
```php
|
||||
$user->setDn($dn);
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
#### Modifying a DN From A Model
|
||||
|
||||
When you've received a model from a search result, you can build and modify the models DN like so:
|
||||
|
||||
```php
|
||||
$user = $ad->users()->find('jdoe');
|
||||
|
||||
$dn = $user->getDnBuilder();
|
||||
|
||||
$dn->addOu('Users');
|
||||
|
||||
$user->setDn($dn)->save();
|
||||
```
|
||||
|
||||
#### Retrieving the RDN components
|
||||
|
||||
To retrieve all of the RDN components of a Distinguished Name, call `getComponents()`:
|
||||
|
||||
```php
|
||||
$dn = new Adldap\Models\Attributes\DistinguishedName(
|
||||
'cn=John Doe,ou=Accounting,dc=corp,dc=acme,dc=org'
|
||||
);
|
||||
|
||||
$components = $dn->getComponents();
|
||||
|
||||
var_dump($components);
|
||||
|
||||
// Output:
|
||||
// array:5 [▼
|
||||
// "cn" => array:1 [▼
|
||||
// 0 => "John Doe"
|
||||
// ]
|
||||
// "uid" => []
|
||||
// "ou" => array:1 [▼
|
||||
// 0 => "Accounting"
|
||||
// ]
|
||||
// "dc" => array:3 [▼
|
||||
// 0 => "corp"
|
||||
// 1 => "acme"
|
||||
// 2 => "org"
|
||||
// ]
|
||||
// "o" => []
|
||||
// ]
|
||||
```
|
||||
|
||||
You can also specify a component you would like returned by supplying it as an argument:
|
||||
|
||||
```php
|
||||
$dn = new Adldap\Models\Attributes\DistinguishedName(
|
||||
'cn=John Doe,ou=Accounting,dc=corp,dc=acme,dc=org'
|
||||
);
|
||||
|
||||
$dcs = $dn->getComponents('dc');
|
||||
|
||||
var_dump($dcs);
|
||||
|
||||
// Output:
|
||||
// array:3 [▼
|
||||
// 0 => "corp"
|
||||
// 1 => "acme"
|
||||
// 2 => "org"
|
||||
// ]
|
||||
```
|
175
data/web/inc/lib/vendor/adldap2/adldap2/docs/events.md
vendored
Normal file
175
data/web/inc/lib/vendor/adldap2/adldap2/docs/events.md
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
# Events
|
||||
|
||||
Adldap2 events provide a method of listening for certain LDAP actions
|
||||
that are called and execute tasks for that specific event.
|
||||
|
||||
> **Note**: The Adldap2 event dispatcher was actually derived from the
|
||||
> [Laravel Framework](https://github.com/laravel/framework) with
|
||||
> Broadcasting & Queuing omitted to remove extra dependencies
|
||||
> that would be required with implementing those features.
|
||||
>
|
||||
> If you've utilized Laravel's events before, this will feel very familiar.
|
||||
|
||||
## Registering Listeners
|
||||
|
||||
> **Note**: Before we get to registering listeners, it's crucial to know that events throughout
|
||||
> Adldap2 are fired irrespective of the current connection or provider in use.
|
||||
>
|
||||
> This means that when using multiple LDAP connections, the same events will be fired.
|
||||
>
|
||||
> This allows you to set listeners on events that occur for all LDAP connections you utilize.
|
||||
>
|
||||
> If you are required to determine which events are fired from alternate connections, see [below](#determining-the-connection).
|
||||
|
||||
To register a listener on an event, retrieve the event dispatcher and call the `listen()` method:
|
||||
|
||||
```php
|
||||
use Adldap\Auth\Events\Binding;
|
||||
|
||||
$dispatcher = \Adldap\Adldap::getEventDispatcher();
|
||||
|
||||
$dispatcher->listen(Binding::class, function (Binding $event) {
|
||||
// Do something with the Binding event information:
|
||||
|
||||
$event->connection; // Adldap\Connections\Ldap instance
|
||||
$event->username; // 'jdoe@acme.org'
|
||||
$event->password; // 'super-secret'
|
||||
});
|
||||
```
|
||||
|
||||
The first argument is the event name you would like to listen for, and the
|
||||
second is either a closure or class name that should handle the event:
|
||||
|
||||
Using a class:
|
||||
|
||||
> **Note**: When using just a class name, the class must contain a public `handle()` method that will handle the event.
|
||||
|
||||
```php
|
||||
use Adldap\Adldap;
|
||||
use Adldap\Auth\Events\Binding;
|
||||
|
||||
$dispatcher = Adldap::getEventDispatcher();
|
||||
|
||||
$dispatcher->listen(Binding::class, MyApp\BindingEventHandler::class);
|
||||
```
|
||||
|
||||
```php
|
||||
namespace MyApp;
|
||||
|
||||
use Adldap\Auth\Events\Binding;
|
||||
|
||||
class BindingEventHandler
|
||||
{
|
||||
public function handle(Binding $event)
|
||||
{
|
||||
// Handle the event...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Model Events
|
||||
|
||||
Model events are handled the same way as authentication events.
|
||||
|
||||
Simply call the event dispatcher `listen()` method with the model event you are wanting to listen for:
|
||||
|
||||
```php
|
||||
use Adldap\Models\Events\Saving;
|
||||
|
||||
$dispatcher = \Adldap\Adldap::getEventDispatcher();
|
||||
|
||||
$dispatcher->listen(Saving::class, function (Saving $event) {
|
||||
// Do something with the Saving event information:
|
||||
|
||||
// Returns the model instance being saved eg. `Adldap\Models\Entry`
|
||||
$event->getModel();
|
||||
});
|
||||
```
|
||||
|
||||
## Wildcard Event Listeners
|
||||
|
||||
You can register listeners using the `*` as a wildcard parameter to catch multiple events with the same listener.
|
||||
|
||||
Wildcard listeners will receive the event name as their first argument, and the entire event data array as their second argument:
|
||||
|
||||
```php
|
||||
$dispatcher = Adldap::getEventDispatcher();
|
||||
|
||||
// Listen for all model events.
|
||||
$dispatcher->listen('Adldap\Models\Events\*', function ($eventName, array $data) {
|
||||
echo $eventName; // Returns 'Adldap\Models\Events\Updating'
|
||||
var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating;
|
||||
});
|
||||
|
||||
$user = $provider->search()->users()->find('jdoe');
|
||||
|
||||
$user->setTelephoneNumber('555 555-5555');
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
## Determining the Connection
|
||||
|
||||
If you're using multiple LDAP connections and you require the ability to determine which events belong
|
||||
to a certain connection, you can do so by verifying the host of the LDAP connection.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```php
|
||||
$dispatcher = Adldap::getEventDispatcher();
|
||||
|
||||
$dispatcher->listen(\Adldap\Models\Events\Creating::class, function ($event) {
|
||||
$connection = $event->model->getConnection();
|
||||
|
||||
$host = $connection->getHost();
|
||||
|
||||
echo $host; // Displays 'ldap://192.168.1.1:386'
|
||||
});
|
||||
```
|
||||
|
||||
Another example with auth events:
|
||||
|
||||
```php
|
||||
$dispatcher = Adldap::getEventDispatcher();
|
||||
|
||||
$dispatcher->listen(\Adldap\Auth\Events\Binding::class, function ($event) {
|
||||
$connection = $event->connection;
|
||||
|
||||
$host = $connection->getHost();
|
||||
|
||||
echo $host; // Displays 'ldap://192.168.1.1:386'
|
||||
});
|
||||
```
|
||||
|
||||
## List of Events
|
||||
|
||||
### Authentication Events
|
||||
|
||||
There are several events that are fired during initial and subsequent binds to your configured LDAP server.
|
||||
|
||||
Here is a list of all events that are fired:
|
||||
|
||||
| Event| Description |
|
||||
|---|---|
|
||||
| Adldap\Auth\Events\Attempting | When any authentication attempt is called via: `$provider->auth()->attempt()` |
|
||||
| Adldap\Auth\Events\Passed | When any authentication attempts pass via: `$provider->auth()->attempt()` |
|
||||
| Adldap\Auth\Events\Failed | When any authentication attempts fail via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
|
||||
| Adldap\Auth\Events\Binding | When any LDAP bind attempts occur via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
|
||||
| Adldap\Auth\Events\Bound | When any LDAP bind attempts are successful via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
|
||||
|
||||
### Model Events
|
||||
|
||||
There are several events that are fired during the creation, updating and deleting of all models.
|
||||
|
||||
Here is a list of all events that are fired:
|
||||
|
||||
| Event | Description |
|
||||
|---|---|
|
||||
| Adldap\Models\Events\Saving | When a model is in the process of being saved via: `$model->save()` |
|
||||
| Adldap\Models\Events\Saved | When a model has been successfully saved via: `$model->save()` |
|
||||
| Adldap\Models\Events\Creating | When a model is being created via: `$model->save()` *Or* `$model->create()` |
|
||||
| Adldap\Models\Events\Created | When a model has been successfully created via: `$model->save()` *Or* `$model->create()` |
|
||||
| Adldap\Models\Events\Updating | When a model is being updated via: `$model->save()` *Or* `$model->update()` |
|
||||
| Adldap\Models\Events\Updated | When a model has been successfully updated via: `$model->save()` *Or* `$model->update()` |
|
||||
| Adldap\Models\Events\Deleting | When a model is being deleted via: `$model->delete()` |
|
||||
| Adldap\Models\Events\Deleted | When a model has been successfully deleted via: `$model->delete()` |
|
35
data/web/inc/lib/vendor/adldap2/adldap2/docs/index.html
vendored
Normal file
35
data/web/inc/lib/vendor/adldap2/adldap2/docs/index.html
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Adldap2 Documentation</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="description" content="Adldap2 Documentation">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="https://unpkg.com/docsify/lib/themes/vue.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'Adldap2',
|
||||
repo: 'https://github.com/Adldap2/Adldap2',
|
||||
autoHeader: true,
|
||||
auto2top: true,
|
||||
homepage: 'readme.md',
|
||||
coverpage: true,
|
||||
search: 'auto',
|
||||
loadSidebar: true,
|
||||
subMaxLevel: 3
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="https://unpkg.com/prismjs/components/prism-php.min.js"></script>
|
||||
<script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
</body>
|
||||
</html>
|
29
data/web/inc/lib/vendor/adldap2/adldap2/docs/installation.md
vendored
Normal file
29
data/web/inc/lib/vendor/adldap2/adldap2/docs/installation.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# Requirements
|
||||
|
||||
Adldap2 requires the following:
|
||||
|
||||
- PHP 7.0 or greater
|
||||
- LDAP extension enabled in PHP
|
||||
- An LDAP server (ActiveDirectory, OpenLDAP, FreeIPA etc.)
|
||||
|
||||
# Composer
|
||||
|
||||
Adldap2 uses [Composer](https://getcomposer.org) for installation.
|
||||
|
||||
Once you have composer installed, run the following command in the root directory of your project:
|
||||
|
||||
```bash
|
||||
composer require adldap2/adldap2
|
||||
```
|
||||
|
||||
Then, if your application doesn't already require Composer's autoload, you will need to do it manually.
|
||||
|
||||
Insert this line at the top of your projects PHP script (usually `index.php`):
|
||||
|
||||
```php
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
```
|
||||
|
||||
You're all set!
|
||||
|
||||
Now, head over to the [setup guide](setup.md) to get up and running.
|
74
data/web/inc/lib/vendor/adldap2/adldap2/docs/logging.md
vendored
Normal file
74
data/web/inc/lib/vendor/adldap2/adldap2/docs/logging.md
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
# Logging
|
||||
|
||||
Adldap2 includes an implementation of PSR's widely supported [Logger](https://github.com/php-fig/log) interface.
|
||||
|
||||
By default, all of Adldap2's [events](events.md) will call the logger you have set to utilize.
|
||||
|
||||
> **Note**: Adldap2 does not include a file / text logger. You must implement your own.
|
||||
|
||||
## Registering & Enabling a Logger
|
||||
|
||||
To register a logger call `Adldap::setLogger()`. The logger must implement the `Psr\Log\LoggerInterface`.
|
||||
|
||||
>**Note**: Be sure to set the logger prior to creating a new `Adldap` instance. This
|
||||
> ensures all events throughout the lifecycle of the request use your logger.
|
||||
|
||||
```php
|
||||
use Adldap\Adldap;
|
||||
|
||||
Adldap::setLogger($myLogger);
|
||||
|
||||
$config = ['...'];
|
||||
|
||||
$ad = new Adldap();
|
||||
|
||||
$ad->addProvider($config);
|
||||
```
|
||||
|
||||
## Disabling Logging
|
||||
|
||||
If you need to disable the event logger after a certain set of operations, simply pass in `null` and logging will be disabled:
|
||||
|
||||
```php
|
||||
use Adldap\Adldap;
|
||||
|
||||
Adldap::setLogger($myLogger);
|
||||
|
||||
$config = ['...'];
|
||||
|
||||
$ad = new Adldap();
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
try {
|
||||
$ad->connect();
|
||||
|
||||
// Disable logging anything else.
|
||||
Adldap::setLogger(null);
|
||||
} catch (\Adldap\Connections\BindException $e) {
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
## Logged Information
|
||||
|
||||
Here is a list of events that are logged along with the information included:
|
||||
|
||||
| Authentication Events | Logged |
|
||||
|---|---|
|
||||
| `Adldap\Auth\Events\Attempting` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Attempting - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
|
||||
| `Adldap\Auth\Events\Binding` |` LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Binding - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
|
||||
| `Adldap\Auth\Events\Bound` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Bound - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
|
||||
| `Adldap\Auth\Events\Passed` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Passed - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
|
||||
| `Adldap\Auth\Events\Failed` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Failed - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org - Result: Invalid Credentials` |
|
||||
|
||||
| Model Events | Logged |
|
||||
|---|---|
|
||||
| `Adldap\Models\Events\Saving` | `LDAP (ldap://192.168.1.1:389) - Operation: Saving - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Saved` | `LDAP (ldap://192.168.1.1:389) - Operation: Saved - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Creating` | `LDAP (ldap://192.168.1.1:389) - Operation: Creating - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Created` | `LDAP (ldap://192.168.1.1:389) - Operation: Created - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Updating` | `LDAP (ldap://192.168.1.1:389) - Operation: Updating - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Updated` | `LDAP (ldap://192.168.1.1:389) - Operation: Updated - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Deleting` | `LDAP (ldap://192.168.1.1:389) - Operation: Deleting - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
||||
| `Adldap\Models\Events\Deleted` | `LDAP (ldap://192.168.1.1:389) - Operation: Deleted - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
|
1
data/web/inc/lib/vendor/adldap2/adldap2/docs/media/bg.svg
vendored
Normal file
1
data/web/inc/lib/vendor/adldap2/adldap2/docs/media/bg.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%' viewBox='0 0 1600 800'><rect fill='#46ff55' width='1600' height='800'/><g ><path fill='#51ff76' d='M486 705.8c-109.3-21.8-223.4-32.2-335.3-19.4C99.5 692.1 49 703 0 719.8V800h843.8c-115.9-33.2-230.8-68.1-347.6-92.2C492.8 707.1 489.4 706.5 486 705.8z'/><path fill='#57ff94' d='M1600 0H0v719.8c49-16.8 99.5-27.8 150.7-33.5c111.9-12.7 226-2.4 335.3 19.4c3.4 0.7 6.8 1.4 10.2 2c116.8 24 231.7 59 347.6 92.2H1600V0z'/><path fill='#5affb1' d='M478.4 581c3.2 0.8 6.4 1.7 9.5 2.5c196.2 52.5 388.7 133.5 593.5 176.6c174.2 36.6 349.5 29.2 518.6-10.2V0H0v574.9c52.3-17.6 106.5-27.7 161.1-30.9C268.4 537.4 375.7 554.2 478.4 581z'/><path fill='#57ffcd' d='M0 0v429.4c55.6-18.4 113.5-27.3 171.4-27.7c102.8-0.8 203.2 22.7 299.3 54.5c3 1 5.9 2 8.9 3c183.6 62 365.7 146.1 562.4 192.1c186.7 43.7 376.3 34.4 557.9-12.6V0H0z'/><path fill='#50ffe8' d='M181.8 259.4c98.2 6 191.9 35.2 281.3 72.1c2.8 1.1 5.5 2.3 8.3 3.4c171 71.6 342.7 158.5 531.3 207.7c198.8 51.8 403.4 40.8 597.3-14.8V0H0v283.2C59 263.6 120.6 255.7 181.8 259.4z'/><path fill='#7dffe9' d='M1600 0H0v136.3c62.3-20.9 127.7-27.5 192.2-19.2c93.6 12.1 180.5 47.7 263.3 89.6c2.6 1.3 5.1 2.6 7.7 3.9c158.4 81.1 319.7 170.9 500.3 223.2c210.5 61 430.8 49 636.6-16.6V0z'/><path fill='#9effe9' d='M454.9 86.3C600.7 177 751.6 269.3 924.1 325c208.6 67.4 431.3 60.8 637.9-5.3c12.8-4.1 25.4-8.4 38.1-12.9V0H288.1c56 21.3 108.7 50.6 159.7 82C450.2 83.4 452.5 84.9 454.9 86.3z'/><path fill='#baffea' d='M1600 0H498c118.1 85.8 243.5 164.5 386.8 216.2c191.8 69.2 400 74.7 595 21.1c40.8-11.2 81.1-25.2 120.3-41.7V0z'/><path fill='#d2ffea' d='M1397.5 154.8c47.2-10.6 93.6-25.3 138.6-43.8c21.7-8.9 43-18.8 63.9-29.5V0H643.4c62.9 41.7 129.7 78.2 202.1 107.4C1020.4 178.1 1214.2 196.1 1397.5 154.8z'/><path fill='#e9ffeb' d='M1315.3 72.4c75.3-12.6 148.9-37.1 216.8-72.4h-723C966.8 71 1144.7 101 1315.3 72.4z'/></g></svg>
|
32
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/computer.md
vendored
Normal file
32
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/computer.md
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# The Computer Model
|
||||
|
||||
> **Note**: This model contains the traits `HasDescription`, `HasLastLogonAndLogOff` & `HasCriticalSystemObject`.
|
||||
> For more information, visit the documentation:
|
||||
>
|
||||
> [HasDescription](/models/traits/has-description.md),
|
||||
> [HasLastLogonAndLogOff](/models/traits/has-last-login-last-logoff.md),
|
||||
> [HasCriticalSystemObject](/models/traits/has-critical-system-object.md)
|
||||
|
||||
## Methods
|
||||
|
||||
```php
|
||||
$computer = $provider->search()->computers()->find('ACME-EXCHANGE');
|
||||
|
||||
// Returns 'Windows Server 2003'
|
||||
$computer->getOperatingSystem();
|
||||
|
||||
// Returns '5.2 (3790)';
|
||||
$computer->getOperatingSystemVersion();
|
||||
|
||||
// Returns 'Service Pack 1';
|
||||
$computer->getOperatingSystemServicePack();
|
||||
|
||||
// Returns 'ACME-DESKTOP001.corp.acme.org'
|
||||
$computer->getDnsHostName();
|
||||
|
||||
$computer->getLastLogOff();
|
||||
|
||||
$computer->getLastLogon();
|
||||
|
||||
$computer->getLastLogonTimestamp();
|
||||
```
|
13
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/contact.md
vendored
Normal file
13
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/contact.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# The Contact Model
|
||||
|
||||
The Contact model extends from the base `Adldap\Models\Model` class and contains
|
||||
no specific methods / attributes that are limited to it.
|
||||
|
||||
## Creation
|
||||
|
||||
```php
|
||||
// Adldap\Models\Contact
|
||||
$contact = $provider->make()->contact([
|
||||
'cn' => 'Suzy Doe',
|
||||
]);
|
||||
```
|
24
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/container.md
vendored
Normal file
24
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/container.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# The Container Model
|
||||
|
||||
> **Note**: This model contains the trait `HasDescription` & `HasCriticalSystemObject`.
|
||||
> For more information, visit the documentation:
|
||||
>
|
||||
> [HasDescription](/models/traits/has-description.md),
|
||||
> [HasCriticalSystemObject](/models/traits/has-critical-system-object.md),
|
||||
|
||||
## Creation
|
||||
|
||||
```php
|
||||
// Adldap\Models\Container
|
||||
$container = $provider->make()->container([
|
||||
'cn' => 'VPN Users',
|
||||
]);
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
The `Container` model contains only one unique method.
|
||||
|
||||
```php
|
||||
$flags = $container->getSystemFlags();
|
||||
```
|
253
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/group.md
vendored
Normal file
253
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/group.md
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
# The Group Model
|
||||
|
||||
> **Note**: This model contains the trait `HasMemberOf`.
|
||||
> For more information, visit the documentation:
|
||||
>
|
||||
> [HasMemberOf](/models/traits/has-member-of.md)
|
||||
|
||||
## Creation
|
||||
|
||||
```php
|
||||
// Adldap\Models\Group
|
||||
$group = $provider->make()->group([
|
||||
'cn' => 'Managers',
|
||||
]);
|
||||
|
||||
// Create group's DN through the DN Builder:
|
||||
$group = $provider->make()->group();
|
||||
|
||||
$dn = $group->getDnBuilder();
|
||||
|
||||
$dn->addOu('Workstation Computers');
|
||||
|
||||
$dn->addCn("Managers");
|
||||
|
||||
$group->setDn($dn);
|
||||
|
||||
// Or set the DN manually:
|
||||
$ou->setDn('cn=Managers,ou=Workstation Computers,dc=test,dc=local,dc=com');
|
||||
|
||||
$group->save();
|
||||
```
|
||||
|
||||
## Getting a groups members
|
||||
|
||||
When you receive a `Group` model instance, it will contain a `member`
|
||||
attribute which contains the distinguished names of all
|
||||
the members inside the group.
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->first();
|
||||
|
||||
foreach ($group->members as $member) {
|
||||
echo $member; // 'cn=John Doe,dc=corp,dc=acme,dc=org'
|
||||
}
|
||||
```
|
||||
|
||||
But this might not be useful, since we might actually want the models for each member.
|
||||
|
||||
This can be easily done with the `getMembers()` method on the group.
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->first();
|
||||
|
||||
foreach ($group->getMembers() as $member) {
|
||||
echo get_class($member); // Instance of `Adldap\Models\Model`
|
||||
|
||||
echo $member->getCommonName();
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: You should be aware however, that calling the `getMembers()` method will
|
||||
> query your `AD` server for **every** member contained in the group to retrieve
|
||||
> its model. For larger group sets it may be worth paginating them.
|
||||
|
||||
|
||||
### Paginating Group Members
|
||||
|
||||
The group you're looking for might contain hundreds / thousands of members.
|
||||
|
||||
In this case, your server might only return you a portion of the groups members.
|
||||
|
||||
To get around this limit, you need to ask your server to paginate the groups members through a select:
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->select('member;range=0-500')->first();
|
||||
|
||||
foreach ($group->members as $member) {
|
||||
// We'll only have 500 members in this query.
|
||||
}
|
||||
```
|
||||
|
||||
Now, when we have the group instance, we'll only have the first `500` members inside this group.
|
||||
However, calling the `getMembers()` method will automatically retrieve the rest of the members for you:
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->select('member;range=0-500')->first();
|
||||
|
||||
foreach ($group->getMembers() as $member) {
|
||||
// Adldap will automatically retrieve the next 500
|
||||
// records until it's retrieved all records.
|
||||
$member->getCommonName();
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: Groups containing large amounts of users (1000+) will require
|
||||
> more memory assigned to PHP. Your mileage will vary.
|
||||
|
||||
#### Paginating large sets of Group Members
|
||||
|
||||
When requesting group members from groups that contain a large amount of members
|
||||
(typically over 1000), you may receive PHP memory limit errors due to
|
||||
the large amount of the objects being created in the request.
|
||||
|
||||
To resolve this, you will need to retrieve the members manually. However using
|
||||
this route you will only be able to retrieve the members distinguished names.
|
||||
|
||||
```php
|
||||
$from = 0;
|
||||
$to = 500;
|
||||
$range = "member;range=$from-$to";
|
||||
|
||||
// Retrieve the group.
|
||||
$group = $provider->search()->select($range)->raw()->find('Accounting');
|
||||
|
||||
// Remove the count from the member array.
|
||||
unset($group[$range]['count']);
|
||||
|
||||
// The array of group members distinguished names.
|
||||
$members = $group[$range];
|
||||
|
||||
foreach ($members as $member) {
|
||||
echo $member; // 'cn=John Doe,dc=acme,dc=org'
|
||||
}
|
||||
```
|
||||
|
||||
You can then encapsulate the above example into a recursive function to retrieve the remaining group members.
|
||||
|
||||
## Getting only a groups member names
|
||||
|
||||
To retrieve only the names of the members contained in a group, call the `getMemberNames()` method:
|
||||
|
||||
```php
|
||||
foreach ($group->getMemberNames() as $name) {
|
||||
// Returns 'John Doe'
|
||||
echo $name;
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: This method does not query your server for each member to retrieve its name. It
|
||||
> only parses the distinguished names from the groups `member` attribute. This means that
|
||||
> if you have paginated group members, you will need to perform another query yourself
|
||||
> to retrieve the rest of the member names (or just call the `getMembers()` method).
|
||||
|
||||
## Setting Group Members
|
||||
|
||||
To set members that are apart of the group, you can perform this in two ways:
|
||||
|
||||
> **Note**: Remember, this will remove **all** pre-existing members, and set the new given members on the group.
|
||||
|
||||
```php
|
||||
$members = [
|
||||
'cn=John Doe,dc=corp,dc=acme,dc=org',
|
||||
'cn=Jane Doe,dc=corp,dc=acme,dc=org',
|
||||
];
|
||||
|
||||
$group->setMembers($members);
|
||||
|
||||
$group->save();
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```php
|
||||
$group->member = [
|
||||
'cn=John Doe,dc=corp,dc=acme,dc=org',
|
||||
'cn=Jane Doe,dc=corp,dc=acme,dc=org',
|
||||
];
|
||||
|
||||
$group->save();
|
||||
```
|
||||
|
||||
## Adding One Member
|
||||
|
||||
To add a single member to a group, use the `addMember()` method:
|
||||
|
||||
> **Note**: You do not need to call the `save()` method after adding a
|
||||
> member. It's automatically called so you can determine
|
||||
> if the member was successfully added.
|
||||
|
||||
```php
|
||||
// We can provide a model, or just a plain DN of the new member
|
||||
$user = $provider->search()->users()->first();
|
||||
|
||||
if ($group->addMember($user)) {
|
||||
// User was successfully added to the group!
|
||||
}
|
||||
|
||||
// Or
|
||||
|
||||
$user = 'cn=John Doe,dc=corp,dc=acme,dc=org';
|
||||
|
||||
if ($group->addMember($user)) {
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
## Adding Multiple Group Members
|
||||
|
||||
To add multiple members to a group, use the `addMembers()` method:
|
||||
|
||||
> **Note**: You do not need to call the `save()` method after adding
|
||||
> members. It's automatically called so you can determine
|
||||
> if the members were successfully added.
|
||||
|
||||
```php
|
||||
$members = [
|
||||
'cn=John Doe,dc=corp,dc=acme,dc=org',
|
||||
'cn=Jane Doe,dc=corp,dc=acme,dc=org',
|
||||
];
|
||||
|
||||
$group->addMembers($members);
|
||||
|
||||
// Or
|
||||
|
||||
$user = $provider->search()->users()->first();
|
||||
|
||||
if ($group->addMembers($user)) {
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
## Removing One Member
|
||||
|
||||
To remove a single member to a group, use the `removeMember()` method:
|
||||
|
||||
```php
|
||||
// We can provide a model, or just a plain DN of the existing member
|
||||
$group = $provider->search()->groups()->first();
|
||||
|
||||
$member = $group->getMembers()->first();
|
||||
|
||||
if ($group->removeMember($member)) {
|
||||
// Member was successfully removed from the group!
|
||||
}
|
||||
|
||||
// Or
|
||||
|
||||
$user = 'cn=John Doe,dc=corp,dc=acme,dc=org';
|
||||
|
||||
if ($group->removeMember($user)) {
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
## Removing All Members
|
||||
|
||||
To remove all members, use the `removeMembers()` method:
|
||||
|
||||
```php
|
||||
if ($group->removeMembers()) {
|
||||
// All members were successfully removed!
|
||||
}
|
||||
```
|
655
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/model.md
vendored
Normal file
655
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/model.md
vendored
Normal file
@ -0,0 +1,655 @@
|
||||
# Creating / Updating
|
||||
|
||||
## Introduction
|
||||
|
||||
Adldap2 implements the [ActiveRecord](https://en.wikipedia.org/wiki/Active_record_pattern) pattern.
|
||||
This means that each LDAP record in your directory is represented as it's own model instance.
|
||||
|
||||
## Creating
|
||||
|
||||
Creating LDAP entries manually is always a pain, but Adldap2 makes it effortless. Let's get started.
|
||||
|
||||
When you have a provider instance, call the `make()` method. This returns an `Adldap\Models\Factory` instance:
|
||||
|
||||
```php
|
||||
$factory = $provider->make();
|
||||
```
|
||||
|
||||
Or you can chain all methods if you'd prefer:
|
||||
|
||||
```php
|
||||
$user = $provider->make()->user();
|
||||
```
|
||||
|
||||
### Available Make Methods
|
||||
|
||||
When calling a make method, all of them accept an `$attributes` parameter
|
||||
to fill the model with your specified attributes.
|
||||
|
||||
```php
|
||||
// Adldap\Models\User
|
||||
$user = $provider->make()->user([
|
||||
'cn' => 'John Doe',
|
||||
]);
|
||||
|
||||
// Adldap\Models\Computer
|
||||
$computer = $provider->make()->computer([
|
||||
'cn' => 'COMP-101',
|
||||
]);
|
||||
|
||||
// Adldap\Models\Contact
|
||||
$contact = $provider->make()->contact([
|
||||
'cn' => 'Suzy Doe',
|
||||
]);
|
||||
|
||||
// Adldap\Models\Container
|
||||
$container = $provider->make()->container([
|
||||
'cn' => 'VPN Users',
|
||||
]);
|
||||
|
||||
// Adldap\Models\Group
|
||||
$group = $provider->make()->group([
|
||||
'cn' => 'Managers',
|
||||
]);
|
||||
|
||||
// Adldap\Models\OrganizationalUnit
|
||||
$ou = $provider->make()->ou([
|
||||
'name' => 'Acme',
|
||||
]);
|
||||
```
|
||||
|
||||
## Saving
|
||||
|
||||
When you have any model instance, you can call the `save()` method to persist the
|
||||
changes to your server. This method returns a `boolean`. For example:
|
||||
|
||||
```php
|
||||
$user = $provider->make()->user([
|
||||
'cn' => 'New User',
|
||||
]);
|
||||
|
||||
if ($user->save()) {
|
||||
// User was saved.
|
||||
} else {
|
||||
// There was an issue saving this user.
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: When a model is saved successfully (whether created or updated), the
|
||||
> models attributes are re-synced in the background from your LDAP server.
|
||||
>
|
||||
> This allows you to perform other operations during the same
|
||||
> request that require an existing model.
|
||||
|
||||
### Creating (Manually)
|
||||
|
||||
If you are sure the model **does not exist** already inside your LDAP directory, you can use the `create()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->make()->user([
|
||||
'cn' => 'New User',
|
||||
]);
|
||||
|
||||
if ($user->create()) {
|
||||
// User was created.
|
||||
} else {
|
||||
// There was an issue creating this user.
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: When you call the create method, if the model does not have a
|
||||
> distinguished name, one will automatically be generated for you using your
|
||||
> `base_dn` set in your configuration and the models common name.
|
||||
|
||||
### Updating (Manually)
|
||||
|
||||
If you are sure the model **does exist** already inside your LDAP directory, you can use the `update()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->whereEquals('cn', 'John Doe')->firstOrFail();
|
||||
|
||||
$user->displayName = 'Suzy Doe';
|
||||
|
||||
if ($user->update()) {
|
||||
// User was updated.
|
||||
} else {
|
||||
// There was an issue updating this user.
|
||||
}
|
||||
```
|
||||
|
||||
## Checking Existence
|
||||
|
||||
If you need to check the existence of a model, use the property `exists`.
|
||||
|
||||
How does it know if the model exists in your LDAP directory? Well, when models are constructed from
|
||||
search results, the `exists` property on the model is set to `true`.
|
||||
|
||||
```php
|
||||
$user = $provider->search()->find('jdoe');
|
||||
|
||||
$user->exists; // Returns true.
|
||||
|
||||
if ($user->delete()) {
|
||||
$user->exists; // Returns false.
|
||||
}
|
||||
```
|
||||
|
||||
If a model is created successfully, the `exists` property is set to `true`:
|
||||
|
||||
```php
|
||||
$user = $provider->make()->user([
|
||||
'cn' => 'John Doe',
|
||||
]);
|
||||
|
||||
$user->exists; // Returns false.
|
||||
|
||||
if ($user->save()) {
|
||||
$user->exists; // Returns true.
|
||||
}
|
||||
```
|
||||
|
||||
## Attributes
|
||||
|
||||
Due to LDAPs multi-valued nature, all LDAP attributes inside a model have their own array.
|
||||
|
||||
For example, a models attributes may contain the following:
|
||||
|
||||
```php
|
||||
var_dump($user->getAttributes());
|
||||
|
||||
// Returns:
|
||||
/*
|
||||
[
|
||||
'cn' => [
|
||||
0 => 'John Doe',
|
||||
],
|
||||
'sn' => [
|
||||
0 => 'Doe',
|
||||
],
|
||||
'givenname' => [
|
||||
0 => 'John'
|
||||
],
|
||||
'useraccountcontrol' => [
|
||||
0 => 512
|
||||
],
|
||||
'mail' => [
|
||||
0 => 'jdoe@acme.org',
|
||||
1 => 'john-doe@acme.org',
|
||||
],
|
||||
'memberof' => [
|
||||
0 => 'cn=Accountants,ou=Groups,dc=acme,dc=org',
|
||||
1 => 'cn=Employees,ou=Groups,dc=acme,dc=org',
|
||||
2 => 'cn=Users,ou=Groups,dc=acme,dc=org',
|
||||
],
|
||||
]
|
||||
*/
|
||||
```
|
||||
|
||||
You can notice in the above dumped array that each attribute contains
|
||||
its own array with a value assigned to the first key.
|
||||
|
||||
Since all models extend from the base class `Adldap\Models\Model`, there
|
||||
are many useful methods that you can use on every model to easily
|
||||
retrieve these attributes you're looking for.
|
||||
|
||||
### Getting Attributes
|
||||
|
||||
You can get attributes in a few ways:
|
||||
|
||||
```php
|
||||
// Returns an array all of the users attributes.
|
||||
$user->getAttributes();
|
||||
|
||||
// Returns an array of all the users email addresses.
|
||||
// Returns `null` if non-existent.
|
||||
$user->getAttribute('mail');
|
||||
|
||||
// Returns the users first email address.
|
||||
// Returns `null` if non-existent.
|
||||
$user->getAttribute('mail', 0);
|
||||
|
||||
// Returns the users first email address.
|
||||
// Returns `null` if non-existent.
|
||||
$user->getFirstAttribute('mail');
|
||||
|
||||
// Returns an array of all the users email addresses.
|
||||
$user->mail;
|
||||
|
||||
// Returns the users first email address.
|
||||
$user->mail[0];
|
||||
```
|
||||
|
||||
#### Using a Getter
|
||||
|
||||
Some attributes have methods for easier retrieval so you don't need to look up the LDAP attribute name.
|
||||
|
||||
For example, to retrieve a users email address, use the method `getEmail()`:
|
||||
|
||||
```php
|
||||
$user->getEmail();
|
||||
```
|
||||
|
||||
##### Other Methods
|
||||
|
||||
The following methods are available on all returned models:
|
||||
|
||||
```php
|
||||
// Returns the model's 'name' attribute.
|
||||
$model->getName();
|
||||
|
||||
// Returns the model's 'cn' attribute.
|
||||
$model->getCommonName();
|
||||
|
||||
// Returns the model's 'displayname' attribute.
|
||||
$model->getDisplayName();
|
||||
|
||||
// Returns the model's 'samaccountname' attriubte.
|
||||
$model->getAccountName();
|
||||
|
||||
// Returns the model's 'samaccounttype` attribute.
|
||||
$model->getAccountType();
|
||||
|
||||
// Returns the model's 'whencreated` attribute.
|
||||
$model->getCreatedAt();
|
||||
|
||||
// Returns the model's 'whencreated` attribute in a MySQL timestamp format.
|
||||
$model->getCreatedAtDate();
|
||||
|
||||
// Returns the model's 'whencreated' attribute in unix time.
|
||||
$model->getCreatedAtTimestamp();
|
||||
|
||||
// Returns the model's 'whenchanged` attribute.
|
||||
$model->getUpdatedAt();
|
||||
|
||||
// Returns the model's 'whenchanged` attribute in a MySQL timestamp format.
|
||||
$model->getUpdatedAtDate();
|
||||
|
||||
// Returns the model's 'whenchanged` attribute in unix time.
|
||||
$model->getUpdatedAtTimestamp();
|
||||
|
||||
// Returns the model's 'objectclass' attribute.
|
||||
$model->getObjectClass();
|
||||
|
||||
// Returns the model's root object category string.
|
||||
$model->getObjectCategory();
|
||||
|
||||
// Returns the model's object category in an array.
|
||||
$model->getObjectCategoryArray();
|
||||
|
||||
// Returns the model's object category distinguished name.
|
||||
$model->getObjectCategoryDn();
|
||||
|
||||
// Returns the model's SID in binary.
|
||||
$model->getObjectSid();
|
||||
|
||||
// Returns the model's GUID in binary.
|
||||
$model->getObjectGuid();
|
||||
|
||||
// Returns the model's SID in a string.
|
||||
$model->getConvertedSid();
|
||||
|
||||
// Returns the model's GUID in a string.
|
||||
$model->getConvertedGuid();
|
||||
|
||||
// Returns the model's primary group ID.
|
||||
$model->getPrimaryGroupId();
|
||||
|
||||
// Returns the model's 'instancetype' attribute.
|
||||
$model->getInstanceType();
|
||||
|
||||
// Returns the model's 'maxpwdage' attribute.
|
||||
$model->getMaxPasswordAge();
|
||||
```
|
||||
|
||||
For more documentation on specific getters, please take a look at the relevant model documentation.
|
||||
|
||||
#### Getting Dirty (Modified) Attributes
|
||||
|
||||
You can get a models modified attributes using the `getDirty()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->users()->find('john');
|
||||
|
||||
// Returns array [0 => 'John Doe']
|
||||
var_dump($user->cn);
|
||||
|
||||
$user->setAttribute('cn', 'Jane Doe');
|
||||
|
||||
// Returns array ['cn' => [0 => 'Jane Doe']]
|
||||
var_dump($user->getDirty());
|
||||
|
||||
// The attribute has been modified - returns array [0 => 'Jane Doe']
|
||||
var_dump($user->cn);
|
||||
```
|
||||
|
||||
The method returns an array with the key being the modified attribute,
|
||||
and the array being the new values of the attribute.
|
||||
|
||||
#### Getting Original (Unmodified) Attributes
|
||||
|
||||
You can get a models original attributes using the `getOriginal()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->users()->find('john');
|
||||
|
||||
// Returns array [0 => 'John Doe']
|
||||
var_dump($user->cn);
|
||||
|
||||
$user->setAttribute('cn', 'Jane Doe');
|
||||
|
||||
// The attribute has been modified - returns array [0 => 'Jane Doe']
|
||||
var_dump($user->cn);
|
||||
|
||||
// Retrieving the original value - returns array [0 => 'John Doe']
|
||||
var_dump($user->getOriginal()['cn']);
|
||||
```
|
||||
|
||||
> **Note**: Keep in mind, when you `save()` a model, the models original
|
||||
> attributes will be re-synchronized to the models new attributes.
|
||||
|
||||
### Setting Attributes
|
||||
|
||||
Just like getting model attributes, there's multiple ways of setting attributes as well:
|
||||
|
||||
```php
|
||||
// Setting via method:
|
||||
$user->setAttribute('cn', 'John Doe');
|
||||
|
||||
// Specifying a subkey for overwriting specific attributes:
|
||||
$user->setAttribute('mail', 'other-mail@mail.com', 0);
|
||||
|
||||
// Setting the first attribute:
|
||||
$user->setFirstAttribute('mail', 'jdoe@mail.com');
|
||||
|
||||
// Setting via property:
|
||||
$user->cn = 'John Doe';
|
||||
|
||||
// Mass setting attributes:
|
||||
$user->fill([
|
||||
'cn' => 'John Doe',
|
||||
'mail' => 'jdoe@mail.com',
|
||||
]);
|
||||
```
|
||||
|
||||
#### Setting Boolean Attributes
|
||||
|
||||
When setting boolean attribute values, you cannot use `0` / `1` / `true` / `false` as these
|
||||
are simply converted to integer values when saving and your LDAP server will
|
||||
likely return an error for doing so on certain attributes.
|
||||
|
||||
You will need to use the string versions of the boolean (`'TRUE'` / `'FALSE'`) for the
|
||||
boolean attribute to be set properly on your LDAP server.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```php
|
||||
$user->setFirstAttribute('msExchHideFromAddressLists', 'TRUE');
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
### Creating Attributes
|
||||
|
||||
To create an attribute that does not exist on the model, you can set it like a regular property:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->whereEquals('cn', 'John Doe')->firstOrFail();
|
||||
|
||||
$user->new = 'New Attribute';
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
If the set attribute does not exist on the model already,
|
||||
it will automatically be created when you call the `save()` method.
|
||||
|
||||
If you'd like manually create new attributes individually, call the `createAttribute($attribute, $value)` method:
|
||||
|
||||
```php
|
||||
if ($user->createAttribute('new', 'New Attribute')) {
|
||||
// Attribute created.
|
||||
}
|
||||
```
|
||||
|
||||
### Updating Attributes
|
||||
|
||||
To modify an attribute you can either use a setter method, or by setting it manually:
|
||||
|
||||
> **Note**: You can also utilize setters to create new attributes if your model does not already have the attribute.
|
||||
|
||||
```php
|
||||
$user = $provider->search()->whereEquals('cn', 'John Doe')->firstOrFail();
|
||||
|
||||
$user->cn = 'New Name';
|
||||
|
||||
// Or use a setter:
|
||||
|
||||
$user->setCommonName('New Name');
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
If you'd like to update attributes individually, call the `updateAttribute($attribute, $value)` method:
|
||||
|
||||
```php
|
||||
if ($user->updateAttribute('cn', 'New Name')) {
|
||||
// Successfully updated attribute.
|
||||
}
|
||||
```
|
||||
|
||||
### Removing Attributes
|
||||
|
||||
To remove attributes, set the attribute to `NULL`:
|
||||
|
||||
```php
|
||||
$user->cn = null;
|
||||
|
||||
$user->save();
|
||||
```
|
||||
|
||||
Or, you can call the `deleteAttribute($attribute)` method:
|
||||
|
||||
```php
|
||||
if ($user->deleteAttribute('cn')) {
|
||||
// Attribute has been deleted.
|
||||
}
|
||||
```
|
||||
|
||||
### Checking Attributes
|
||||
|
||||
#### Checking Existence of Attributes
|
||||
|
||||
To see if a model contains an attribute, use the method `hasAttribute()`:
|
||||
|
||||
```php
|
||||
// Checking if a base attribute exists:
|
||||
if ($user->hasAttribute('mail')) {
|
||||
// This user contains an email address.
|
||||
}
|
||||
|
||||
// Checking if a sub attribute exists, by key:
|
||||
if ($user->hasAttribute('mail', 1)) {
|
||||
// This user contains a second email address.
|
||||
}
|
||||
```
|
||||
|
||||
#### Counting the Models Attributes
|
||||
|
||||
To retrieve the total number of attributes, use the method `countAttributes()`:
|
||||
|
||||
```php
|
||||
$count = $user->countAttributes();
|
||||
|
||||
var_dump($count); // Returns int
|
||||
```
|
||||
|
||||
#### Checking if a Model is contained in an OU
|
||||
|
||||
To check if a model is located inside an OU, use the `inOu()` method:
|
||||
|
||||
```php
|
||||
if ($model->inOu('User Accounts')) {
|
||||
// This model is inside the 'User Accounts' OU.
|
||||
}
|
||||
```
|
||||
|
||||
You can also use an OU model instance:
|
||||
|
||||
```php
|
||||
$serviceAccounts = $provider->search()->ous()->find('Service Accounts');
|
||||
|
||||
if ($model->inOu($serviceAccounts)) {
|
||||
// This model is inside the 'Service Accounts' OU.
|
||||
}
|
||||
```
|
||||
|
||||
#### Checking if a Model is Writable
|
||||
|
||||
To check if the model can be written to, use the method `isWritable()`:
|
||||
|
||||
```php
|
||||
if ($model->isWritable()) {
|
||||
// You can modify this model.
|
||||
}
|
||||
```
|
||||
|
||||
### Force Re-Syncing A Models Attributes
|
||||
|
||||
If you need to forcefully re-sync a models attributes, use the method `syncRaw()`:
|
||||
|
||||
```php
|
||||
$user->syncRaw();
|
||||
```
|
||||
|
||||
> **Note**: This will query your LDAP server for the current model, and re-synchronize
|
||||
> it's attributes. This is only recommended if your creating / updating / deleting
|
||||
> attributes manually through your LDAP connection.
|
||||
|
||||
## Moving / Renaming
|
||||
|
||||
To move a user from one DN or OU to another, use the `move()` method:
|
||||
|
||||
> **Note**: The `move()` method is actually an alias for the `rename()` method.
|
||||
|
||||
```php
|
||||
// New parent distiguished name.
|
||||
$newParentDn = 'OU=New Ou,DC=corp,DC=local';
|
||||
|
||||
if ($user->move($newParentDn)) {
|
||||
// User was successfully moved to the new OU.
|
||||
}
|
||||
```
|
||||
|
||||
You can also provide a model to move the child model into:
|
||||
|
||||
```php
|
||||
// New parent OU.
|
||||
$newParentOu = $provider->search()->ous()->find('Accounting');
|
||||
|
||||
if ($user->move($newParentOu)) {
|
||||
// User was successfully moved to the new OU.
|
||||
}
|
||||
```
|
||||
|
||||
If you would like to keep the models old RDN along side their new RDN, pass in false in the second parameter:
|
||||
|
||||
```php
|
||||
// New parent distiguished name.
|
||||
$newParentDn = 'OU=New Ou,DC=corp,DC=local';
|
||||
|
||||
if ($user->move($newParentDn, $deleteOldRdn = false)) {
|
||||
// User was successfully moved to the new OU,
|
||||
// and their old RDN has been left in-tact.
|
||||
}
|
||||
```
|
||||
|
||||
To rename a users DN, just pass in their new relative distinguished name in the `rename()` method:
|
||||
|
||||
```php
|
||||
$newRdn = 'cn=New Name';
|
||||
|
||||
if ($user->rename($newRdn)) {
|
||||
// User was successfully renamed.
|
||||
}
|
||||
```
|
||||
|
||||
## Deleting
|
||||
|
||||
To delete a model, just call the `delete()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->whereEquals('cn', 'John Doe')->firstOrFail();
|
||||
|
||||
echo $user->exists; // Returns true.
|
||||
|
||||
if ($user->delete()) {
|
||||
// Successfully deleted user.
|
||||
|
||||
echo $user->exists; // Returns false.
|
||||
}
|
||||
```
|
||||
|
||||
## Extending
|
||||
|
||||
> **Note**: This feature was introduced in `v8.0.0`.
|
||||
|
||||
To use your own models, you will need to create a new [Schema](../schema.md).
|
||||
|
||||
Once you have created your own schema, you must insert it inside the construct of your provider.
|
||||
|
||||
Let's walk through this process.
|
||||
|
||||
First we'll create our model we'd like to extend / override:
|
||||
|
||||
> **Note**: Your custom model **must** extend from an existing Adldap2 model.
|
||||
> This is due to methods and attributes that only exist on these classes.
|
||||
|
||||
```php
|
||||
namespace App\Ldap\Models;
|
||||
|
||||
use Adldap\Models\User as Model;
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
public function getCommonName()
|
||||
{
|
||||
// Overriding model method.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, we'll create our custom schema and return our models class name:
|
||||
|
||||
```php
|
||||
namespace App\Ldap\Schemas;
|
||||
|
||||
use App\Ldap\Models\User;
|
||||
|
||||
class LdapSchema extends ActiveDirectory
|
||||
{
|
||||
public function userModel()
|
||||
{
|
||||
return User::class;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, when we create a provider, we need to insert our Schema into the configuration:
|
||||
|
||||
```php
|
||||
$config = [
|
||||
'hosts' => ['...'],
|
||||
|
||||
'username' => 'admin',
|
||||
'password' => 'P@ssword',
|
||||
|
||||
'schema' => MyApp\LdapSchema::class,
|
||||
];
|
||||
|
||||
$ad = new Adldap($config);
|
||||
|
||||
$provider = $ad->connect();
|
||||
|
||||
// If `jdoe` exists, your custom model will be returned.
|
||||
$user = $provider->search()->users()->find('jdoe');
|
||||
```
|
19
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/organization.md
vendored
Normal file
19
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/organization.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# The Organization Model
|
||||
|
||||
The Organization model extends from the base `Adldap\Models\Model` class and contains
|
||||
no specific methods / attributes that are limited to it.
|
||||
|
||||
## Creation
|
||||
|
||||
```php
|
||||
// Adldap\Models\Organization
|
||||
$org = $provider->make()->organization([
|
||||
'o' => 'Some Company',
|
||||
]);
|
||||
|
||||
// Set the DN manually:
|
||||
|
||||
$org->setDn('o=Some Company,dc=test,dc=local,dc=com');
|
||||
|
||||
$org->save();
|
||||
```
|
27
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/ou.md
vendored
Normal file
27
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/ou.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# The OrganizationalUnit Model
|
||||
|
||||
The OrganizationalUnit model extends from the base `Adldap\Models\Model` class and contains
|
||||
no specific methods / attributes that are limited to it.
|
||||
|
||||
## Creation
|
||||
|
||||
```php
|
||||
// Adldap\Models\OrganizationalUnit
|
||||
$ou = $provider->make()->ou([
|
||||
'name' => 'Workstation Computers',
|
||||
]);
|
||||
|
||||
// Generate the OU's DN through the DN Builder:
|
||||
|
||||
$dn = $ou->getDnBuilder();
|
||||
|
||||
$dn->addOu('Workstation Computers');
|
||||
|
||||
$ou->setDn($dn);
|
||||
|
||||
// Or set the DN manually:
|
||||
|
||||
$ou->setDn('ou=Workstation Computers,dc=test,dc=local,dc=com');
|
||||
|
||||
$ou->save();
|
||||
```
|
49
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/printer.md
vendored
Normal file
49
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/printer.md
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
# The Printer Model
|
||||
|
||||
## Methods
|
||||
|
||||
```php
|
||||
$printer->getPrinterName();
|
||||
|
||||
$printer->getPrinterShareName();
|
||||
|
||||
$printer->getMemory();
|
||||
|
||||
$printer->getUrl();
|
||||
|
||||
$printer->getLocation();
|
||||
|
||||
$printer->getServerName();
|
||||
|
||||
$printer->getColorSupported();
|
||||
|
||||
$printer->getDuplexSupported();
|
||||
|
||||
$printer->getMediaSupported();
|
||||
|
||||
$printer->getStaplingSupported();
|
||||
|
||||
$printer->getPrintBinNames();
|
||||
|
||||
$printer->getPrintMaxResolution();
|
||||
|
||||
$printer->getPrintOrientations();
|
||||
|
||||
$printer->getDriverName();
|
||||
|
||||
$printer->getDriverVersion();
|
||||
|
||||
$printer->getPriority();
|
||||
|
||||
$printer->getPrintStartTime();
|
||||
|
||||
$printer->getPrintEndTime();
|
||||
|
||||
$printer->getPortName();
|
||||
|
||||
$printer->getVersionNumber();
|
||||
|
||||
$printer->getPrintRate();
|
||||
|
||||
$printer->getPrintRateUnit();
|
||||
```
|
33
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/root-dse.md
vendored
Normal file
33
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/root-dse.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# The RootDse Model
|
||||
|
||||
## Getting the Root DSE
|
||||
|
||||
To get the Root DSE of your LDAP server, call the `getRootDse()` method off a new search:
|
||||
|
||||
```php
|
||||
$rootDse = $provider->search()->getRootDse();
|
||||
```
|
||||
|
||||
## Getting the schema naming context
|
||||
|
||||
To get the Root DSE schema naming context, call the `getSchemaNamingContext()`:
|
||||
|
||||
```php
|
||||
$rootDse = $provider->search()->getRootDse();
|
||||
|
||||
$context = $rootDse->getSchemaNamingContext();
|
||||
|
||||
// Returns 'cn=Schema,cn=Configuration,dc=corp,dc=acme,dc=org'
|
||||
echo $context;
|
||||
```
|
||||
|
||||
## Getting the root domain naming context
|
||||
|
||||
To get the Root DSE domain naming context, call the `getRootDomainNamingContext()`:
|
||||
|
||||
```php
|
||||
$context = $rootDse->getRootDomainNamingContext();
|
||||
|
||||
// Returns 'dc=corp,dc=acme,dc=org'
|
||||
echo $context;
|
||||
```
|
13
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-critical-system-object.md
vendored
Normal file
13
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-critical-system-object.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# HasCriticalSystemObject Trait
|
||||
|
||||
Models that contain this trait, have the `isCriticalSystemObject` attribute.
|
||||
|
||||
There is only one method that accompanies this trait:
|
||||
|
||||
```php
|
||||
if ($model->isCriticalSystemObject()) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
11
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-description.md
vendored
Normal file
11
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-description.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# HasDescription Trait
|
||||
|
||||
Models that contain this trait, have the `description` attribute.
|
||||
|
||||
There are only two methods that accompany this trait:
|
||||
|
||||
```php
|
||||
$model->getDescription();
|
||||
|
||||
$model->setDescription('The models description');
|
||||
```
|
16
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-last-login-last-logoff.md
vendored
Normal file
16
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-last-login-last-logoff.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# HasLastLoginAndLastLogoff Trait
|
||||
|
||||
Models that contain this trait have the `lastlogoff`, `lastlogon` and `lastlogontimestamp` attributes.
|
||||
|
||||
## Methods
|
||||
|
||||
```php
|
||||
// Returns the models's last log off attribute.
|
||||
$computer->getLastLogOff();
|
||||
|
||||
// Returns the models's last log on attribute.
|
||||
$computer->getLastLogon();
|
||||
|
||||
// Returns the models's last log on timestamp attribute.
|
||||
$computer->getLastLogonTimestamp();
|
||||
```
|
166
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-member-of.md
vendored
Normal file
166
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/traits/has-member-of.md
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
# HasMemberOf Trait
|
||||
|
||||
Models that contain this trait, have the ability to be apart of a group.
|
||||
|
||||
There's many helpful methods to assist you in all of the operations related to group membership, let's get started!
|
||||
|
||||
## Retrieving Groups
|
||||
|
||||
To retrieve the groups that a model is apart of, call the `getGroups()` method:
|
||||
|
||||
```php
|
||||
$user = $provider->search()->users()->find('jdoe');
|
||||
|
||||
$groups = $user->getGroups();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
|
||||
$group->getCommonName(); // ex. 'Accounting'
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
We can also pass in specific fields we need from the returned groups to speed up our queries.
|
||||
|
||||
For example, if we only need the groups common name:
|
||||
|
||||
```php
|
||||
// Group models will be returned with only their common name.
|
||||
$groups = $user->getGroups(['cn']);
|
||||
```
|
||||
|
||||
However, calling `getGroups()` will only retrieve the models immediate groups (non-recursive).
|
||||
|
||||
To retrieve nested groups, pass in `true` into the second parameter:
|
||||
|
||||
```php
|
||||
$groups = $user->getGroups([], $recursive = true);
|
||||
```
|
||||
|
||||
## Retrieve Group Names
|
||||
|
||||
If you only want the models group names, call the `getGroupNames()` method:
|
||||
|
||||
```php
|
||||
$names = $user->getGroupNames();
|
||||
|
||||
foreach ($names as $name) {
|
||||
|
||||
echo $name; // ex. 'Accounting'
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
However, this method will also retrieve only the immediate groups names
|
||||
much like the `getGroups()` method. You'll need to pass in `true` in
|
||||
the first parameter to retrieve results recursively.
|
||||
|
||||
```php
|
||||
$names = $user->getGroupNames($recursive = true);
|
||||
```
|
||||
|
||||
## Checking if the Model is apart of a Group
|
||||
|
||||
To check if a model is apart of a certain group, use the `inGroup()` method:
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->find('Office');
|
||||
|
||||
if ($user->inGroup($group)) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
You can also check for multiple memberships by passing in an array of groups:
|
||||
|
||||
```php
|
||||
$groups = $provider->search()->findManyBy('cn', ['Accounting', 'Office']));
|
||||
|
||||
if ($user->inGroup($groups->toArray()) {
|
||||
|
||||
// This user is apart of the 'Accounting' and 'Office' group!
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: Much like the other methods above, you'll need to provide a `$recursive`
|
||||
> flag to the `inGroup()` method if you'd like recursive results included.
|
||||
|
||||
We can also provide distinguished names instead of Group model instances:
|
||||
|
||||
```php
|
||||
$dns = [
|
||||
'cn=Accounting,ou=Groups,dc=acme,dc=org',
|
||||
'cn=Office,ou=Groups,dc=acme,dc=org',
|
||||
];
|
||||
|
||||
if ($user->inGroup($dns, $recursive = true)) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Or, we can also just provide the name(s) of the group(s).
|
||||
|
||||
```php
|
||||
$names = [
|
||||
'Accounting',
|
||||
'Office',
|
||||
];
|
||||
|
||||
if ($user->inGroup($names, $recursive = true)) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Adding a Group
|
||||
|
||||
To add the model to a specific group, call the `addGroup()` method:
|
||||
|
||||
```php
|
||||
$group = $provider->search()->groups()->find('Accounting');
|
||||
|
||||
// You can either provide a Group model:
|
||||
if ($user->addGroup($group)) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
// Or a Groups DN:
|
||||
if ($user->addGroup('cn=Accounting,ou=Groups,dc=acme,dc=org')) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: You do not need to call the `save()` method for adding / removing groups.
|
||||
> This is done automatically so you can perform clean `if` statements on the method.
|
||||
|
||||
## Removing a Group
|
||||
|
||||
To remove the model from a specific group, call the `removeGroup()` method:
|
||||
|
||||
```php
|
||||
$group = $user->getGroups()->first();
|
||||
|
||||
// You can either provide a Group model:
|
||||
if ($user->removeGroup($group)) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
// Or the groups DN:
|
||||
if ($user->removeGroup('cn=Accounting,ou=Office Groups,dc=acme,dc=org')) {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
```
|
180
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/user.md
vendored
Normal file
180
data/web/inc/lib/vendor/adldap2/adldap2/docs/models/user.md
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
# The User Model
|
||||
|
||||
> **Note**: This model contains the trait `HasMemberOf`. For more information, visit the documentation:
|
||||
> [HasMemberOfTrait](/models/traits/has-member-of.md)
|
||||
|
||||
## Creating
|
||||
|
||||
> **Note**: If you need to create users with passwords, SSL or TLS **must** be enabled on your configured connection.
|
||||
>
|
||||
> The password you enter for the user **must** also obey your LDAP servers password requirements,
|
||||
> otherwise you will receive a "Server is unwilling to perform" LDAP exception upon saving.
|
||||
|
||||
```php
|
||||
// Construct a new User model instance.
|
||||
$user = $provider->make()->user();
|
||||
|
||||
// Create the users distinguished name.
|
||||
// We're adding an OU onto the users base DN to have it be saved in the specified OU.
|
||||
$dn = $user->getDnBuilder()->addOu('Users'); // Built DN will be: "CN=John Doe,OU=Users,DC=acme,DC=org";
|
||||
|
||||
// Set the users DN, account name.
|
||||
$user->setDn($dn);
|
||||
$user->setAccountName('jdoe');
|
||||
$user->setCommonName('John Doe');
|
||||
|
||||
// Set the users password.
|
||||
// NOTE: This password must obey your AD servers password requirements
|
||||
// (including password history, length, special characters etc.)
|
||||
// otherwise saving will fail and you will receive an
|
||||
// "LDAP Server is unwilling to perform" message.
|
||||
$user->setPassword('correct-horse-battery-staple');
|
||||
|
||||
// Get a new account control object for the user.
|
||||
$ac = $user->getUserAccountControlObject();
|
||||
|
||||
// Mark the account as enabled (normal).
|
||||
$ac->accountIsNormal();
|
||||
|
||||
// Set the account control on the user and save it.
|
||||
$user->setUserAccountControl($ac);
|
||||
|
||||
// Save the user.
|
||||
$user->save();
|
||||
|
||||
// All done! An enabled user will be created and is ready for use.
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
There's a ton of available methods for the User model. Below is a list for a quick reference.
|
||||
|
||||
> **Note**: Don't see a method for an LDAP attribute? Create an issue and let us know!
|
||||
|
||||
```php
|
||||
// Get the users display name.
|
||||
$user->getDisplayName();
|
||||
|
||||
// Get the users first email address.
|
||||
$user->getEmail();
|
||||
|
||||
// Get the users title.
|
||||
$user->getTitle();
|
||||
|
||||
// Get the users department.
|
||||
$user->getDepartment();
|
||||
|
||||
// Get the users first name.
|
||||
$user->getFirstName();
|
||||
|
||||
// Get the users last name.
|
||||
$user->getLastName();
|
||||
|
||||
// Get the users info.
|
||||
$user->getInfo();
|
||||
|
||||
// Get the users initials.
|
||||
$user->getInitials();
|
||||
|
||||
// Get the users country.
|
||||
$user->getCountry();
|
||||
|
||||
// Get the users street address.
|
||||
$user->getStreetAddress();
|
||||
|
||||
// Get the users postal code.
|
||||
$user->getPostalCode();
|
||||
|
||||
// Get the users physical delivery office name.
|
||||
$user->getPhysicalDeliveryOfficeName();
|
||||
|
||||
// Get the users phone number.
|
||||
$user->getTelephoneNumber();
|
||||
|
||||
// Get the users locale.
|
||||
$user->getLocale();
|
||||
|
||||
// Get the users company.
|
||||
$user->getCompany();
|
||||
|
||||
// Get the users other email addresses.
|
||||
$user->getOtherMailbox();
|
||||
|
||||
// Get the users home mailbox database location (stored as a distinguished name).
|
||||
$user->getHomeMdb();
|
||||
|
||||
// Get the users email nickname.
|
||||
$user->getMailNickname();
|
||||
|
||||
// Get the users principal name.
|
||||
$user->getUserPrincipalName();
|
||||
|
||||
// Get the users proxy email addresses.
|
||||
$user->getProxyAddresses();
|
||||
|
||||
// Get the users failed login attempts.
|
||||
$user->getBadPasswordCount();
|
||||
|
||||
// Get the users last failed login attempt timestamp.
|
||||
$user->getBadPasswordTime();
|
||||
|
||||
// Get the users last password change timestamp.
|
||||
$user->getPasswordLastSet();
|
||||
|
||||
// Get the users last password change timestamp in unix time.
|
||||
$user->getPasswordLastSetTimestamp();
|
||||
|
||||
// Get the users last password change timestamp in MySQL date format.
|
||||
$user->getPasswordLastSetDate();
|
||||
|
||||
// Get the users lockout time.
|
||||
$user->getLockoutTime();
|
||||
|
||||
// Get the users user account control integer.
|
||||
$user->getUserAccountControl();
|
||||
|
||||
// Get the users roaming profile path.
|
||||
$user->getProfilePath();
|
||||
|
||||
// Get the users legacy exchange distinguished name.
|
||||
$user->getLegacyExchangeDn();
|
||||
|
||||
// Get the users account expiry timestamp.
|
||||
$user->getAccountExpiry();
|
||||
|
||||
// Get the boolean that determines whether to show this user in the global address book.
|
||||
$user->getShowInAddressBook();
|
||||
|
||||
// Get the users thumbnail photo.
|
||||
$user->getThumbnail();
|
||||
|
||||
// Get the users thumbnail photo (base64 encoded for HTML <img src=""> tags).
|
||||
$user->getThumbnailEncoded();
|
||||
|
||||
// Get the users jpeg photo.
|
||||
$user->getJpegPhoto();
|
||||
|
||||
// Get the users jpeg photo (base64 encoded for HTML <img src=""> tags).
|
||||
$user->getJpegPhotoEncoded();
|
||||
|
||||
// Get the users manager.
|
||||
$user->getManager();
|
||||
|
||||
// Get the users employee ID.
|
||||
$user->getEmployeeId();
|
||||
|
||||
// Get the users employee number.
|
||||
$user->getEmployeeNumber();
|
||||
|
||||
// Get the users employee type
|
||||
$user->getEmployeeType();
|
||||
|
||||
// Get the users room number.
|
||||
$user->getRoomNumber();
|
||||
|
||||
// Get the users department number.
|
||||
$user->getDepartmentNumber();
|
||||
|
||||
// Get the users personal title.
|
||||
$user->getPersonalTitle();
|
||||
```
|
115
data/web/inc/lib/vendor/adldap2/adldap2/docs/readme.md
vendored
Normal file
115
data/web/inc/lib/vendor/adldap2/adldap2/docs/readme.md
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
# Introduction
|
||||
|
||||
## What is Adldap2?
|
||||
|
||||
Adldap2 is a PHP LDAP package that allows you to:
|
||||
|
||||
1. Easily manage multiple LDAP connections at once
|
||||
2. Perform authentication
|
||||
3. Search your LDAP directory with a fluent and easy to use query builder
|
||||
4. Create / Update / Delete LDAP entities with ease
|
||||
5. And more
|
||||
|
||||
## History of Adldap2
|
||||
|
||||
Adldap2 was originally created as a fork of the original LDAP library [adLDAP](https://github.com/adldap/adLDAP) due to bugs, and it being completely abandoned.
|
||||
|
||||
Adldap2 contains absolutely no similarities to the original repository, and was built to be as easily accessible as possible, with great documentation, and easily understandable syntax.
|
||||
|
||||
Much of the API was constructed with Ruby's ActiveRecord and Laravel's Eloquent in mind, and to be an answer to the question:
|
||||
|
||||
> _Why can't we use LDAP like we use a database?_
|
||||
|
||||
## Why should you use Adldap2?
|
||||
|
||||
Working with LDAP in PHP can be a messy and confusing endeavor, especially when using multiple connections, creating and managing entities, performing moves, resetting passwords, and performing ACL modifications to user accounts.
|
||||
|
||||
Wrapper classes for LDAP are usually always created in PHP applications.
|
||||
|
||||
Adldap2 allows you to easily manage the above problems without reinventing the wheel for every project.
|
||||
|
||||
## Implementations
|
||||
|
||||
- [Laravel](https://github.com/Adldap2/Adldap2-Laravel)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Install the package via `composer`:
|
||||
|
||||
```
|
||||
composer require adldap2/adldap2
|
||||
```
|
||||
|
||||
Use Adldap2:
|
||||
|
||||
```php
|
||||
// Construct new Adldap instance.
|
||||
$ad = new \Adldap\Adldap();
|
||||
|
||||
// Create a configuration array.
|
||||
$config = [
|
||||
// An array of your LDAP hosts. You can use either
|
||||
// the host name or the IP address of your host.
|
||||
'hosts' => ['ACME-DC01.corp.acme.org', '192.168.1.1'],
|
||||
|
||||
// The base distinguished name of your domain to perform searches upon.
|
||||
'base_dn' => 'dc=corp,dc=acme,dc=org',
|
||||
|
||||
// The account to use for querying / modifying LDAP records. This
|
||||
// does not need to be an admin account. This can also
|
||||
// be a full distinguished name of the user account.
|
||||
'username' => 'admin@corp.acme.org',
|
||||
'password' => 'password',
|
||||
];
|
||||
|
||||
// Add a connection provider to Adldap.
|
||||
$ad->addProvider($config);
|
||||
|
||||
try {
|
||||
// If a successful connection is made to your server, the provider will be returned.
|
||||
$provider = $ad->connect();
|
||||
|
||||
// Performing a query.
|
||||
$results = $provider->search()->where('cn', '=', 'John Doe')->get();
|
||||
|
||||
// Finding a record.
|
||||
$user = $provider->search()->find('jdoe');
|
||||
|
||||
// Creating a new LDAP entry. You can pass in attributes into the make methods.
|
||||
$user = $provider->make()->user([
|
||||
'cn' => 'John Doe',
|
||||
'title' => 'Accountant',
|
||||
'description' => 'User Account',
|
||||
]);
|
||||
|
||||
// Setting a model's attribute.
|
||||
$user->cn = 'John Doe';
|
||||
|
||||
// Saving the changes to your LDAP server.
|
||||
if ($user->save()) {
|
||||
// User was saved!
|
||||
}
|
||||
} catch (\Adldap\Auth\BindException $e) {
|
||||
|
||||
// There was an issue binding / connecting to the server.
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Versioning
|
||||
|
||||
Adldap2 is versioned under the [Semantic Versioning](http://semver.org/) guidelines as much as possible.
|
||||
|
||||
Releases will be numbered with the following format:
|
||||
|
||||
`<major>.<minor>.<patch>`
|
||||
|
||||
And constructed with the following guidelines:
|
||||
|
||||
* Breaking backward compatibility bumps the major and resets the minor and patch.
|
||||
* New additions without breaking backward compatibility bumps the minor and resets the patch.
|
||||
* Bug fixes and misc changes bumps the patch.
|
||||
|
||||
Minor versions are not maintained individually, and you're encouraged to upgrade through to the next minor version.
|
||||
|
||||
Major versions are maintained individually through separate branches.
|
662
data/web/inc/lib/vendor/adldap2/adldap2/docs/searching.md
vendored
Normal file
662
data/web/inc/lib/vendor/adldap2/adldap2/docs/searching.md
vendored
Normal file
@ -0,0 +1,662 @@
|
||||
# Searching
|
||||
|
||||
## Introduction
|
||||
|
||||
Using the Adldap2 query builder makes building LDAP queries feel effortless.
|
||||
|
||||
It allows you to generate LDAP filters using a fluent and
|
||||
convenient interface, similar to Eloquent in Laravel.
|
||||
|
||||
> **Note:** The Adldap2 query builder escapes all fields & values
|
||||
> given to its `where()` methods. There is no need to clean or
|
||||
> escape strings before passing them into the query builder.
|
||||
|
||||
## Creating a new Query
|
||||
|
||||
To create a new search query, call the `search()` method on your connection provider instance:
|
||||
|
||||
```php
|
||||
$search = $provider->search();
|
||||
```
|
||||
|
||||
Or you can chain all your methods if you'd prefer:
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', '=', 'John Doe')->get();
|
||||
```
|
||||
|
||||
## Selects
|
||||
|
||||
> **Note:** Fields are case in-sensitive. For example, you can
|
||||
> insert `CN`, `cn` or `cN`, they will return the same result.
|
||||
|
||||
#### Selecting attributes
|
||||
|
||||
Selecting only the LDAP attributes you need will increase the speed of your queries.
|
||||
|
||||
```php
|
||||
// Passing in an array of attributes
|
||||
$search->select(['cn', 'samaccountname', 'telephone', 'mail']);
|
||||
|
||||
// Passing in each attribute as an argument
|
||||
$search->select('cn', 'samaccountname', 'telephone', 'mail');
|
||||
```
|
||||
|
||||
## Executing Searches
|
||||
|
||||
#### Finding a specific record
|
||||
|
||||
If you're trying to find a single record, but not sure what the record might be, use the `find()` method:
|
||||
|
||||
```php
|
||||
$record = $search->find('John Doe');
|
||||
|
||||
if ($record) {
|
||||
// Record was found!
|
||||
} else {
|
||||
// Hmm, looks like we couldn't find anything...
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: Using the `find()` method will search for LDAP records using ANR
|
||||
> (ambiguous name resolution) and return the first result.
|
||||
>
|
||||
> Since ActiveDirectory is the only LDAP distribution that supports ANR,
|
||||
> an equivalent query will be created for other LDAP distributions
|
||||
> that are not compatible.
|
||||
>
|
||||
> For a more fine-tuned search, use the `findBy()` method below.
|
||||
|
||||
##### Finding a record (or failing)
|
||||
|
||||
If you'd like to try and find a single record and throw an exception when it hasn't been
|
||||
found, use the `findOrFail()` method:
|
||||
|
||||
```php
|
||||
try {
|
||||
|
||||
$record = $search->findOrFail('John Doe');
|
||||
|
||||
} catch (Adldap\Models\ModelNotFoundException $e) {
|
||||
// Record wasn't found!
|
||||
}
|
||||
```
|
||||
|
||||
#### Finding a record by a specific attribute
|
||||
|
||||
If you're looking for a single record with a specific attribute, use the `findBy()` method:
|
||||
|
||||
```php
|
||||
// We're looking for a record with the 'samaccountname' of 'jdoe'.
|
||||
$record = $search->findBy('samaccountname', 'jdoe');
|
||||
```
|
||||
|
||||
##### Finding a record by a specific attribute (or failing)
|
||||
|
||||
If you'd like to try and find a single record by a specific attribute and throw
|
||||
an exception when it cannot be found, use the `findByOrFail()` method:
|
||||
|
||||
```php
|
||||
try {
|
||||
|
||||
$record = $search->findByOrFail('samaccountname', 'jdoe');
|
||||
|
||||
} catch (Adldap\Models\ModelNotFoundException $e) {
|
||||
// Record wasn't found!
|
||||
}
|
||||
```
|
||||
|
||||
#### Finding a record by its distinguished name
|
||||
|
||||
If you're looking for a single record with a specific DN, use the `findByDn()` method:
|
||||
|
||||
```php
|
||||
$record = $search->findByDn('cn=John Doe,dc=corp,dc=org');
|
||||
```
|
||||
|
||||
###### Finding a record by its distinguished name (or failing)
|
||||
|
||||
If you'd like to try and find a single record by a specific DN and throw
|
||||
an exception when it hasn't been found, use the `findByDnOrFail()` method:
|
||||
|
||||
```php
|
||||
try {
|
||||
|
||||
$record = $search->findByDnOrFail('cn=John Doe,dc=corp,dc=org');
|
||||
|
||||
} catch (Adldap\Models\ModelNotFoundException $e) {
|
||||
// Record wasn't found!
|
||||
}
|
||||
```
|
||||
|
||||
#### Retrieving results
|
||||
|
||||
To get the results from a search, simply call the `get()` method:
|
||||
|
||||
```php
|
||||
$results = $search->select(['cn', 'samaccountname'])->get();
|
||||
```
|
||||
|
||||
> **Note**: Executed searches via the `get()` method will return them inside an
|
||||
> `Illuminate\Support\Collection` instance (a glorified array), with allows
|
||||
> you to utilize [some extremely handy methods](https://laravel.com/docs/collections).
|
||||
>
|
||||
> Executed searches via the `first()` method will return **a model instance only**.
|
||||
|
||||
##### Retrieving the first record
|
||||
|
||||
To retrieve the first record of a search, call the `first()` method:
|
||||
|
||||
```php
|
||||
$record = $search->first();
|
||||
```
|
||||
|
||||
> **Note**: If you are using `sortBy()`, calling `first()` will not take this into account. Sorts
|
||||
> are performed **after** retrieving query results. If you would like the first record of
|
||||
> a sorted result set, call `first()` on a `Collection` of returned models.
|
||||
|
||||
###### Retrieving the first record (or failing)
|
||||
|
||||
To retrieve the first record of a search or throw an exception when one isn't found, call the `firstOrFail()` method:
|
||||
|
||||
```php
|
||||
try {
|
||||
|
||||
$record = $search->firstOrFail();
|
||||
|
||||
} catch (Adldap\Models\ModelNotFoundException $e) {
|
||||
// Record wasn't found!
|
||||
}
|
||||
```
|
||||
|
||||
## Limit
|
||||
|
||||
To limit the results records returned from your LDAP server and increase the
|
||||
speed of your queries, you can use the `limit()` method:
|
||||
|
||||
```php
|
||||
// This will only return 5 records that contain the name of 'John':
|
||||
$records = $search->where('cn', 'contains', 'John')->limit(5)->get();
|
||||
```
|
||||
|
||||
## Wheres
|
||||
|
||||
To perform a where clause on the search object, use the `where()` function:
|
||||
|
||||
```php
|
||||
$search->where('cn', '=', 'John Doe');
|
||||
```
|
||||
|
||||
This query would look for a record with the common name of 'John Doe' and return the results.
|
||||
|
||||
We can also perform a 'where equals' without including the operator:
|
||||
|
||||
```php
|
||||
$search->whereEquals('cn', 'John Doe');
|
||||
```
|
||||
|
||||
We can also supply an array of key - value pairs to quickly add multiple wheres:
|
||||
|
||||
```php
|
||||
$wheres = [
|
||||
'cn' => 'John Doe',
|
||||
'samaccountname' => 'jdoe',
|
||||
];
|
||||
|
||||
$search->where($wheres);
|
||||
```
|
||||
|
||||
Or, if you require conditionals, you can quickly add multiple wheres with nested arrays:
|
||||
|
||||
```php
|
||||
$search->where([
|
||||
['cn', '=', 'John Doe'],
|
||||
['manager', '!', 'Suzy Doe'],
|
||||
]);
|
||||
```
|
||||
|
||||
#### Where Starts With
|
||||
|
||||
We could also perform a search for all objects beginning with the common name of 'John' using the `starts_with` operator:
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', 'starts_with', 'John')->get();
|
||||
|
||||
// Or use the method whereStartsWith($attribute, $value):
|
||||
|
||||
$results = $provider->search()->whereStartsWith('cn', 'John')->get();
|
||||
```
|
||||
|
||||
#### Where Ends With
|
||||
|
||||
We can also search for all objects that end with the common name of `Doe` using the `ends_with` operator:
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', 'ends_with', 'Doe')->get();
|
||||
|
||||
// Or use the method whereEndsWith($attribute, $value):
|
||||
|
||||
$results = $provider->search()->whereEndsWith('cn', 'Doe')->get();
|
||||
```
|
||||
|
||||
#### Where Between
|
||||
|
||||
To search for records between two values, use the `whereBetween` method.
|
||||
|
||||
For the example below, we'll retrieve all users who were created between two dates:
|
||||
|
||||
```php
|
||||
$from = (new DateTime('October 1st 2016'))->format('YmdHis.0\Z');
|
||||
$to = (new DateTime('January 1st 2017'))->format('YmdHis.0\Z');
|
||||
|
||||
$users = $provider->search()
|
||||
->users()
|
||||
->whereBetween('whencreated', [$from, $to])
|
||||
->get();
|
||||
```
|
||||
|
||||
#### Where Contains
|
||||
|
||||
We can also search for all objects with a common name that contains `John Doe` using the `contains` operator:
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', 'contains', 'John Doe')->get();
|
||||
|
||||
// Or use the method whereContains($attribute, $value):
|
||||
|
||||
$results = $provider->search()->whereContains('cn', 'John Doe')->get();
|
||||
```
|
||||
|
||||
##### Where Not Contains
|
||||
|
||||
You can use a 'where not contains' to perform the inverse of a 'where contains':
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', 'not_contains', 'John Doe')->get();
|
||||
|
||||
// Or use the method whereNotContains($attribute, $value):
|
||||
|
||||
$results = $provider->search()->whereNotContains('cn', 'John Doe');
|
||||
```
|
||||
|
||||
#### Where Has
|
||||
|
||||
Or we can retrieve all objects that have a common name attribute using the wildcard operator (`*`):
|
||||
|
||||
```php
|
||||
$results = $provider->search()->where('cn', '*')->get();
|
||||
|
||||
// Or use the method whereHas($field):
|
||||
|
||||
$results = $provider->search()->whereHas('cn')->get();
|
||||
```
|
||||
|
||||
This type of filter syntax allows you to clearly see what your searching for.
|
||||
|
||||
##### Where Not Has
|
||||
|
||||
You can use a 'where not has' to perform the inverse of a 'where has':
|
||||
|
||||
```php
|
||||
$results = $provider->search->where('cn', '!*')->get();
|
||||
|
||||
// Or use the method whereNotHas($field):
|
||||
|
||||
$results = $provider->search()->whereNotHas($field)->get();
|
||||
```
|
||||
|
||||
## Or Wheres
|
||||
|
||||
To perform an `or where` clause on the search object, use the `orWhere()` method. However,
|
||||
please be aware this function performs differently than it would on a database.
|
||||
|
||||
For example:
|
||||
|
||||
```php
|
||||
$results = $search
|
||||
->where('cn', '=', 'John Doe')
|
||||
->orWhere('cn', '=', 'Suzy Doe')
|
||||
->get();
|
||||
```
|
||||
|
||||
This query would return no results. Since we're already defining that the common name (`cn`) must equal `John Doe`, applying
|
||||
the `orWhere()` does not amount to 'Look for an object with the common name as "John Doe" OR "Suzy Doe"'. This query would
|
||||
actually amount to 'Look for an object with the common name that <b>equals</b> "John Doe" OR "Suzy Doe"
|
||||
|
||||
To solve the above problem, we would use `orWhere()` for both fields. For example:
|
||||
|
||||
```php
|
||||
$results = $search
|
||||
->orWhere('cn', '=', 'John Doe')
|
||||
->orWhere('cn', '=', 'Suzy Doe')
|
||||
->get();
|
||||
```
|
||||
|
||||
Now, we'll retrieve both John and Suzy's LDAP records, because the common name can equal either.
|
||||
|
||||
> **Note**: You can also use all `where` methods as an or where, for example:
|
||||
> `orWhereHas()`, `orWhereContains()`, `orWhereStartsWith()`, `orWhereEndsWith()`
|
||||
|
||||
## Dynamic Wheres
|
||||
|
||||
To perform a dynamic where, simply suffix a `where` with the field you're looking for.
|
||||
|
||||
This feature was directly ported from Laravel's Eloquent.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```php
|
||||
// This query:
|
||||
$result = $search->where('cn', '=', 'John Doe')->first();
|
||||
|
||||
// Can be converted to:
|
||||
$result = $search->whereCn('John Doe')->first();
|
||||
```
|
||||
|
||||
You can perform this on **any** attribute:
|
||||
|
||||
```php
|
||||
$result = $search->whereTelephonenumber('555-555-5555')->first();
|
||||
```
|
||||
|
||||
You can also chain them:
|
||||
|
||||
```php
|
||||
$result = $search
|
||||
->whereTelephonenumber('555-555-5555')
|
||||
->whereGivenname('John Doe')
|
||||
->whereSn('Doe')
|
||||
->first();
|
||||
```
|
||||
|
||||
You can even perform multiple dynamic wheres by separating your fields by an `And`:
|
||||
|
||||
```php
|
||||
// This would perform a search for a user with the
|
||||
// first name of 'John' and last name of 'Doe'.
|
||||
$result = $search->whereGivennameAndSn('John', 'Doe')->first();
|
||||
```
|
||||
|
||||
## Nested Filters
|
||||
|
||||
By default, the Adldap2 query builder automatically wraps your queries in `and` / `or` filters for you.
|
||||
However, if any further complexity is required, nested filters allow you
|
||||
to construct any query fluently and easily.
|
||||
|
||||
#### andFilter
|
||||
|
||||
The `andFilter` method accepts a closure which allows you to construct a query inside of an `and` LDAP filter:
|
||||
|
||||
```php
|
||||
$query = $provider->search()->newQuery();
|
||||
|
||||
// Creates the filter: (&(givenname=John)(sn=Doe))
|
||||
$results = $query->andFilter(function (Adldap\Query\Builder $q) {
|
||||
|
||||
$q->where('givenname', '=', 'John')
|
||||
->where('sn', '=', 'Doe');
|
||||
|
||||
})->get();
|
||||
```
|
||||
|
||||
The above query would return records that contain the first name `John` **and** the last name `Doe`.
|
||||
|
||||
#### orFilter
|
||||
|
||||
The `orFilter` method accepts a closure which allows you to construct a query inside of an `or` LDAP filter:
|
||||
|
||||
```php
|
||||
$query = $provider->search()->newQuery();
|
||||
|
||||
|
||||
// Creates the filter: (|(givenname=John)(sn=Doe))
|
||||
$results = $query->orFilter(function (Adldap\Query\Builder $q) {
|
||||
|
||||
$q->where('givenname', '=', 'John')
|
||||
->where('sn', '=', 'Doe');
|
||||
|
||||
})->get();
|
||||
```
|
||||
|
||||
The above query would return records that contain the first name `John` **or** the last name `Doe`.
|
||||
|
||||
#### notFilter
|
||||
|
||||
The `notFilter` method accepts a closure which allows you to construct a query inside a `not` LDAP filter:
|
||||
|
||||
```php
|
||||
$query = $provider->search()->newQuery();
|
||||
|
||||
// Creates the filter: (!(givenname=John)(sn=Doe))
|
||||
$results = $query->notFilter(function (Adldap\Query\Builder $q) {
|
||||
|
||||
$q->where('givenname', '=', 'John')
|
||||
->where('sn', '=', 'Doe');
|
||||
|
||||
})->get();
|
||||
```
|
||||
|
||||
The above query would return records that **do not** contain the first name `John` **or** the last name `Doe`.
|
||||
|
||||
#### Complex Nesting
|
||||
|
||||
The above methods `andFilter` / `orFilter` can be chained together and nested
|
||||
as many times as you'd like for larger complex queries:
|
||||
|
||||
```php
|
||||
$query = $provider->search()->newQuery();
|
||||
|
||||
$query = $query->orFilter(function (Adldap\Query\Builder $q) {
|
||||
$q->where('givenname', '=', 'John')->where('sn', '=', 'Doe');
|
||||
})->andFilter(function (Adldap\Query\Builder $q) {
|
||||
$q->where('department', '=', 'Accounting')->where('title', '=', 'Manager');
|
||||
})->getUnescapedQuery();
|
||||
|
||||
echo $query; // Returns '(&(|(givenname=John)(sn=Doe))(&(department=Accounting)(title=Manager)))'
|
||||
```
|
||||
|
||||
## Raw Filters
|
||||
|
||||
> **Note**: Raw filters are not escaped. **Do not** accept user input into the raw filter method.
|
||||
|
||||
Sometimes you might just want to add a raw filter without using the query builder.
|
||||
You can do so by using the `rawFilter()` method:
|
||||
|
||||
```php
|
||||
$filter = '(samaccountname=jdoe)';
|
||||
|
||||
$results = $search->rawFilter($filter)->get();
|
||||
|
||||
// Or use an array
|
||||
$filters = [
|
||||
'(samaccountname=jdoe)',
|
||||
'(surname=Doe)',
|
||||
];
|
||||
|
||||
$results = $search->rawFilter($filters)->get();
|
||||
|
||||
// Or use multiple arguments
|
||||
$results = $search->rawFilter($filters[0], $filters[1])->get();
|
||||
|
||||
// Multiple raw filters will be automatically wrapped into an `and` filter:
|
||||
$query = $search->getUnescapedQuery();
|
||||
|
||||
echo $query; // Returns (&(samaccountname=jdoe)(surname=Doe))
|
||||
```
|
||||
|
||||
## Sorting
|
||||
|
||||
Sorting is really useful when your displaying tabular LDAP results. You can
|
||||
easily perform sorts on any LDAP attribute by using the `sortBy()` method:
|
||||
|
||||
```php
|
||||
$results = $search->whereHas('cn')->sortBy('cn', 'asc')->get();
|
||||
```
|
||||
|
||||
You can also sort paginated results:
|
||||
|
||||
```php
|
||||
$results = $search->whereHas('cn')->sortBy('cn', 'asc')->paginate(25);
|
||||
```
|
||||
|
||||
> **Note**: Sorting occurs *after* results are returned. This is due
|
||||
> to PHP not having the functionality of sorting records on
|
||||
> the server side before they are returned.
|
||||
|
||||
## Paginating
|
||||
|
||||
Paginating your search results will allow you to return more results than
|
||||
your LDAP cap (usually 1000) and display your results in pages.
|
||||
|
||||
> **Note**: Calling `paginate()` will retrieve **all** records from your LDAP server for the current query.
|
||||
>
|
||||
> This **does not** operate the same way pagination occurs in a database. Pagination of
|
||||
> an LDAP query simply allows you to return a larger result set than your
|
||||
> LDAP servers configured maximum (usually 1000).
|
||||
>
|
||||
> The pagination object is simply a collection that allows you to iterate
|
||||
> through all the resulting records easily and intuitively.
|
||||
|
||||
To perform this, call the `paginate()` method instead of the `get()` method:
|
||||
|
||||
```php
|
||||
$recordsPerPage = 50;
|
||||
|
||||
$currentPage = $_GET['page'];
|
||||
|
||||
// This would retrieve all records from your LDAP server inside a new Adldap\Objects\Paginator instance.
|
||||
$paginator = $search->paginate($recordsPerPage, $currentPage);
|
||||
|
||||
// Returns total number of pages, int
|
||||
$paginator->getPages();
|
||||
|
||||
// Returns current page number, int
|
||||
$paginator->getCurrentPage();
|
||||
|
||||
// Returns the amount of entries allowed per page, int
|
||||
$paginator->getPerPage();
|
||||
|
||||
// Returns all of the results in the entire paginated result
|
||||
$paginator->getResults();
|
||||
|
||||
// Returns the total amount of retrieved entries, int
|
||||
$paginator->count();
|
||||
|
||||
// Iterate over the results like normal
|
||||
foreach($paginator as $result)
|
||||
{
|
||||
echo $result->getCommonName();
|
||||
}
|
||||
```
|
||||
|
||||
## Scopes
|
||||
|
||||
Search scopes allow you to easily retrieve common models of a particular 'scope'.
|
||||
|
||||
Each scope simply applies the required filters to the search object
|
||||
that (when executed) will only return the relevant models.
|
||||
|
||||
Here is a list of all available scopes:
|
||||
|
||||
```php
|
||||
// Retrieve all users (Adldap\Models\User).
|
||||
$results = $search->users()->get();
|
||||
|
||||
// Retrieve all printers (Adldap\Models\Printer).
|
||||
$results = $search->printers()->get();
|
||||
|
||||
// Retrieve all organizational units (Adldap\Models\OrganizationalUnit).
|
||||
$results = $search->ous()->get();
|
||||
|
||||
// Retrieve all organizational units (Adldap\Models\OrganizationalUnit).
|
||||
$results = $search->organizations()->get();
|
||||
|
||||
// Retrieve all groups (Adldap\Models\Group).
|
||||
$results = $search->groups()->get();
|
||||
|
||||
// Retrieve all containers (Adldap\Models\Container).
|
||||
$results = $search->containers()->get();
|
||||
|
||||
// Retrieve all contacts (Adldap\Models\Contact).
|
||||
$results = $search->contacts()->get();
|
||||
|
||||
// Retrieve all computers (Adldap\Models\Computer).
|
||||
$results = $search->computers()->get();
|
||||
```
|
||||
|
||||
## Base DN
|
||||
|
||||
To set the base DN of your search you can use one of two methods:
|
||||
|
||||
```php
|
||||
// Using the `in()` method:
|
||||
$results = $provider->search()->in('ou=Accounting,dc=acme,dc=org')->get();
|
||||
|
||||
// Using the `setDn()` method:
|
||||
$results = $provider->search()->setDn('ou=Accounting,dc=acme,dc=org')->get();
|
||||
|
||||
// You can also include `in()` with the scope
|
||||
$results = $provider->search()->organizations()->in('ou=Accounting,dc=acme,dc=org')->get()
|
||||
|
||||
```
|
||||
|
||||
Either option will return the same results. Use which ever method you prefer to be more readable.
|
||||
|
||||
## Search Options
|
||||
|
||||
#### Recursive
|
||||
|
||||
By default, all searches performed are recursive.
|
||||
|
||||
If you'd like to disable recursive search and perform a single level search, use the `listing()` method:
|
||||
|
||||
```php
|
||||
$result = $provider->search()->listing()->get();
|
||||
```
|
||||
|
||||
This would perform an `ldap_listing()` instead of an `ldap_search()`.
|
||||
|
||||
#### Read
|
||||
|
||||
If you'd like to perform a read instead of a listing or a recursive search, use the `read()` method:
|
||||
|
||||
```php
|
||||
$result = $provider->search()->read()->where('objectClass', '*')->get();
|
||||
```
|
||||
|
||||
This would perform an `ldap_read()` instead of an `ldap_listing()` or an `ldap_search()`.
|
||||
|
||||
> **Note**: Performing a `read()` will always return *one* record in your result.
|
||||
|
||||
#### Raw
|
||||
|
||||
If you'd like to retrieve the raw LDAP results, use the `raw()` method:
|
||||
|
||||
```php
|
||||
$rawResults = $provider->search()->raw()->where('cn', '=', 'John Doe')->get();
|
||||
|
||||
var_dump($rawResults); // Returns an array
|
||||
```
|
||||
|
||||
## Retrieving the ran query
|
||||
|
||||
If you'd like to retrieve the current query to save or run it at another
|
||||
time, use the `getQuery()` method on the query builder.
|
||||
|
||||
This will return the escaped filter.
|
||||
|
||||
```php
|
||||
$query = $provider->search()->where('cn', '=', 'John Doe')->getQuery();
|
||||
|
||||
echo $query; // Returns '(cn=\4a\6f\68\6e\20\44\6f\65)'
|
||||
```
|
||||
|
||||
To retrieve the unescaped filter, call the `getUnescapedQuery()` method:
|
||||
|
||||
```php
|
||||
$query = $provider->search()->where('cn', '=', 'John Doe')->getUnescapedQuery();
|
||||
|
||||
echo $query; // Returns '(cn=John Doe)'
|
||||
```
|
||||
|
||||
Now that you know how to search your directory, lets move onto [creating / modifying LDAP records](models/model.md).
|
552
data/web/inc/lib/vendor/adldap2/adldap2/docs/setup.md
vendored
Normal file
552
data/web/inc/lib/vendor/adldap2/adldap2/docs/setup.md
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
# Setup
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure your LDAP connections, you can use two methods:
|
||||
|
||||
1. Using an array
|
||||
2. Using a `Adldap\Configuration\DomainConfiguration` object
|
||||
|
||||
Either or will produce the same results. Use whichever you feel most comfortable with.
|
||||
|
||||
### Using an array
|
||||
|
||||
```php
|
||||
$config = [
|
||||
'hosts' => [
|
||||
'DC-01.corp.acme.org',
|
||||
],
|
||||
'...'
|
||||
];
|
||||
```
|
||||
|
||||
### Using a `DomainConfiguration` object
|
||||
|
||||
```php
|
||||
// Setting options via first argument:
|
||||
$config = new Adldap\Configuration\DomainConfiguration([
|
||||
'hosts' => [
|
||||
'DC-01.corp.acme.org',
|
||||
],
|
||||
]);
|
||||
|
||||
// Setting via the `set()` method:
|
||||
$config->set('hosts', [
|
||||
'DC-01.corp.acme.org',
|
||||
]);
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
#### Array Example With All Options
|
||||
|
||||
```php
|
||||
// Create the configuration array.
|
||||
$config = [
|
||||
// Mandatory Configuration Options
|
||||
'hosts' => ['corp-dc1.corp.acme.org', 'corp-dc2.corp.acme.org'],
|
||||
'base_dn' => 'dc=corp,dc=acme,dc=org',
|
||||
'username' => 'admin',
|
||||
'password' => 'password',
|
||||
|
||||
// Optional Configuration Options
|
||||
'schema' => Adldap\Schemas\ActiveDirectory::class,
|
||||
'account_prefix' => 'ACME-',
|
||||
'account_suffix' => '@acme.org',
|
||||
'port' => 389,
|
||||
'follow_referrals' => false,
|
||||
'use_ssl' => false,
|
||||
'use_tls' => false,
|
||||
'version' => 3,
|
||||
'timeout' => 5,
|
||||
|
||||
// Custom LDAP Options
|
||||
'custom_options' => [
|
||||
// See: http://php.net/ldap_set_option
|
||||
LDAP_OPT_X_TLS_REQUIRE_CERT => LDAP_OPT_X_TLS_HARD
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
#### Required Options
|
||||
|
||||
##### Hosts
|
||||
|
||||
The hosts option is an array of IP addresses or hostnames located
|
||||
on your network that serve Active Directory.
|
||||
|
||||
You insert as many servers or as little as you'd like depending on your forest (with the minimum of one of course).
|
||||
|
||||
> **Note:** Do not append your port to your IP addresses or hostnames. Use the `port` configuration option instead.
|
||||
|
||||
##### Base Distinguished Name
|
||||
|
||||
The base distinguished name is the base distinguished name you'd like to perform operations on.
|
||||
|
||||
An example base DN would be `DC=corp,DC=acme,DC=org`.
|
||||
|
||||
If one is not defined, you will not retrieve any search results.
|
||||
|
||||
> **Note**: Your base DN is **case insensitive**. You do not need to worry about incorrect casing.
|
||||
|
||||
##### Username & Password
|
||||
|
||||
To connect to your LDAP server, a username and password is required to be able to query and run operations on your server(s).
|
||||
|
||||
You can use any account that has these permissions.
|
||||
|
||||
> **Note**: To run administration level operations, such as resetting passwords,
|
||||
> this account **must** have permissions to do so on your directory.
|
||||
|
||||
#### Optional Options
|
||||
|
||||
##### Schema
|
||||
|
||||
The schema option allows you to configure which directory you're connecting to.
|
||||
|
||||
This is a somewhat optional, however this **must** be changed if you're connecting
|
||||
to an alternate LDAP variant such as OpenLDAP or FreeIPA.
|
||||
|
||||
Below are available schemas:
|
||||
|
||||
- `Adldap\Schemas\ActiveDirectory`
|
||||
- `Adldap\Schemas\OpenLDAP`
|
||||
- `Adldap\Schemas\FreeIPA`
|
||||
|
||||
By default, this option is set to the `Adldap\Schemas\ActiveDirectory` schema.
|
||||
|
||||
##### Account Prefix
|
||||
|
||||
The account prefix option is a string to *prepend* to all usernames that go through the `Guard::attempt()` method.
|
||||
|
||||
This option is just for convenience.
|
||||
|
||||
It is usually not needed (if utilizing the account suffix), however the functionality is
|
||||
in place if you would like to only allow certain users with the specified prefix
|
||||
to login, or add a domain so your users do not have to specify one.
|
||||
|
||||
##### Account Suffix
|
||||
|
||||
The account suffix option is a string to *append* to all usernames that go
|
||||
through the `Adldap\Auth\Guard::attempt()` method.
|
||||
|
||||
This option is just for convenience.
|
||||
|
||||
An example use case for this would be inserting your LDAP users `userPrincipalName` suffix so you don't need to append it manually.
|
||||
|
||||
For example, with a `account_suffix` in your configuration set to `@corp.acme.org`:
|
||||
|
||||
```php
|
||||
$username = 'jdoe';
|
||||
$password = 'password';
|
||||
|
||||
// Here, an `ldap_bind()` will be called with a username of 'jdoe@corp.acme.org`
|
||||
$provider->auth()->attempt($username, $password);
|
||||
```
|
||||
|
||||
##### Port
|
||||
|
||||
The port option is used for authenticating and binding to your LDAP server.
|
||||
|
||||
The default ports are already used for non SSL and SSL connections (389 and 636).
|
||||
|
||||
Only insert a port if your LDAP server uses a unique port.
|
||||
|
||||
##### Follow Referrals
|
||||
|
||||
The follow referrals option is a boolean to tell active directory to follow a referral to another server on your network if the server queried knows the information your asking for exists, but does not yet contain a copy of it locally.
|
||||
|
||||
This option is defaulted to false.
|
||||
|
||||
Disable this option if you're experiencing search / connectivity issues.
|
||||
|
||||
For more information, visit: https://technet.microsoft.com/en-us/library/cc978014.aspx
|
||||
|
||||
##### SSL & TLS
|
||||
|
||||
These Boolean options enable an SSL or TLS connection to your LDAP server.
|
||||
|
||||
Only **one** can be set to `true`. You must chose either or.
|
||||
|
||||
> **Note**: You **must** enable SSL or TLS to reset passwords in ActiveDirectory.
|
||||
|
||||
These options are definitely recommended if you have the ability to connect to your server securely.
|
||||
|
||||
> **Note**: TLS is recommended over SSL, as SSL is now labelled as a depreciated mechanism for securely running LDAP operations.
|
||||
|
||||
##### Version
|
||||
|
||||
The LDAP version to use for your connection.
|
||||
|
||||
Must be an integer and can either be `2` or `3`.
|
||||
|
||||
##### Timeout
|
||||
|
||||
The timeout option allows you to configure the amount of seconds to wait until
|
||||
your application receives a response from your LDAP server.
|
||||
|
||||
The default is 5 seconds.
|
||||
|
||||
##### Custom Options
|
||||
|
||||
Arbitrary options can be set for the connection to fine-tune TLS and connection behavior.
|
||||
|
||||
Please note that `LDAP_OPT_PROTOCOL_VERSION`, `LDAP_OPT_NETWORK_TIMEOUT` and `LDAP_OPT_REFERRALS` will be ignored if set.
|
||||
|
||||
These are set above with the `version`, `timeout` and `follow_referrals` keys respectively.
|
||||
|
||||
Valid options are listed in the [PHP documentation for ldap_set_option](http://php.net/ldap_set_option).
|
||||
|
||||
## Getting Started
|
||||
|
||||
Each LDAP connection you have will be contained inside the `Adldap` instance as its own **connection provider**.
|
||||
|
||||
There are a couple of ways you can easily add each of your LDAP connections. Let's walk through them:
|
||||
|
||||
**Using a configuration array:**
|
||||
```php
|
||||
$config = ['...'];
|
||||
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
// You can also specify the name of the
|
||||
// connection as the second argument:
|
||||
$ad->addProvider($config, 'connection-one');
|
||||
```
|
||||
|
||||
**Using a DomainConfiguration object:**
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = new Adldap\Configuration\DomainConfiguration(['...']);
|
||||
|
||||
$ad->addProvider($config, 'connection-one');
|
||||
```
|
||||
|
||||
**Using the constructor:**
|
||||
|
||||
> **Note**: When inserting your configuration into a new `Adldap` instance, you
|
||||
> need to set a key for each connection. **This will be its connection name**.
|
||||
|
||||
```php
|
||||
$connections = [
|
||||
'connection1' => [
|
||||
'hosts' => ['...'],
|
||||
],
|
||||
'connection2' => [
|
||||
'hosts' => ['...'],
|
||||
],
|
||||
];
|
||||
|
||||
$ad = new Adldap\Adldap($connections);
|
||||
```
|
||||
|
||||
## Connecting
|
||||
|
||||
The easiest way to get connected is to call the `connect($name)` method on your `Adldap` instance.
|
||||
|
||||
Its first argument accepts the name of your configured connection.
|
||||
|
||||
This method will return you a connected **connection provider** when
|
||||
successful, and throw an exception when unsuccessful:
|
||||
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = ['...'];
|
||||
|
||||
$connectionName = 'my-connection';
|
||||
|
||||
$ad->addProvider($config, $connectionName);
|
||||
|
||||
try {
|
||||
$provider = $ad->connect($connectionName);
|
||||
|
||||
// Great, we're connected!
|
||||
} catch (Adldap\Auth\BindException $e) {
|
||||
// Failed to connect.
|
||||
}
|
||||
```
|
||||
|
||||
### Using an alternate username / password
|
||||
|
||||
If you'd like to connect to your configured connection using a different username and password than your configuration, then simply provide them in the second and third arguments:
|
||||
|
||||
```php
|
||||
$username = 'server-admin';
|
||||
$password = 'my-super-secret-password';
|
||||
|
||||
$provider = $ad->connect($connectionName, $username, $password);
|
||||
```
|
||||
|
||||
### Dynamically Connecting
|
||||
|
||||
If you're like me and like chainable (fluent) API's in PHP, then dynamically connecting is a nice option to have.
|
||||
|
||||
To dynamically connect, simply call any connection provider method on your `Adldap` instance.
|
||||
|
||||
> **Note**: Your default connection will be used when dynamically connecting.
|
||||
> More on this below.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$ad->addProvider($config = ['...']);
|
||||
|
||||
try {
|
||||
$users = $ad->search()->users()->get();
|
||||
} catch (Adldap\Auth\BindException $e) {
|
||||
// Failed to connect.
|
||||
}
|
||||
```
|
||||
|
||||
### Anonymously Binding
|
||||
|
||||
If you'd like to anonymously bind, set your `username` and `password` configuration to `null`:
|
||||
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = [
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
];
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
try {
|
||||
$provider = $ad->connect();
|
||||
|
||||
// ...
|
||||
} catch (BindException $e) {
|
||||
// Failed.
|
||||
}
|
||||
```
|
||||
|
||||
Or, manually bind your provider and don't pass in a `username` or `password` parameter:
|
||||
|
||||
```php
|
||||
$config = [
|
||||
'hosts' => ['...'],
|
||||
];
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
$provider = $ad->getDefaultProvider();
|
||||
|
||||
try {
|
||||
$provider->auth()->bind();
|
||||
|
||||
// Successfully bound.
|
||||
} catch (BindException $e) {
|
||||
// Failed.
|
||||
}
|
||||
```
|
||||
|
||||
### Setting a Default Connection
|
||||
|
||||
Setting a default LDAP connection is used for dynamically connecting.
|
||||
|
||||
To set your default connection, call the `setDefaultProvider($name)` method:
|
||||
|
||||
```php
|
||||
$ad->setDefaultProvider('my-connection');
|
||||
|
||||
$computers = $ad->search()->computers()->get();
|
||||
```
|
||||
|
||||
## Authenticating
|
||||
|
||||
If you're looking to authenticate (bind) users using your LDAP connection, call
|
||||
the `auth()->attempt()` method on your provider instance:
|
||||
|
||||
```php
|
||||
$username = 'jdoe';
|
||||
$password = 'Password@1';
|
||||
|
||||
try {
|
||||
if ($provider->auth()->attempt($username, $password)) {
|
||||
// Passed.
|
||||
} else {
|
||||
// Failed.
|
||||
}
|
||||
} catch (Adldap\Auth\UsernameRequiredException $e) {
|
||||
// The user didn't supply a username.
|
||||
} catch (Adldap\Auth\PasswordRequiredException $e) {
|
||||
// The user didn't supply a password.
|
||||
}
|
||||
```
|
||||
|
||||
If you'd like all LDAP operations during the same request to be ran under the
|
||||
authenticated user, pass in `true` into the last paramter:
|
||||
|
||||
```php
|
||||
if ($provider->auth()->attempt($username, $password, $bindAsUser = true)) {
|
||||
// Passed.
|
||||
} else {
|
||||
// Failed.
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Now that you've learned the basics of configuration and
|
||||
getting yourself connected, continue on to learn
|
||||
[how to search your LDAP directory](searching.md).
|
||||
|
||||
## Using Other LDAP Servers (OpenLDAP / FreeIPA / etc.)
|
||||
|
||||
Alternate LDAP server variants such as OpenLDAP or FreeIPA contain
|
||||
some different attribute names than ActiveDirectory.
|
||||
|
||||
The Adldap2 schema offers an attribute map for each available LDAP attribute, and
|
||||
is completely configurable and customizable.
|
||||
|
||||
If you're using an alternate LDAP server variant such as OpenLDAP or FreeIPA, you **must** change the default schema inside your configuration array. If you do not, you won't receive the correct model instances for results, and you won't be
|
||||
able to utilize some standard methods available on these models.
|
||||
|
||||
By default, Adldap2 is configured to be used with **Microsoft ActiveDirectory**.
|
||||
|
||||
When creating your configuration array, set your schema using the `schema` key:
|
||||
|
||||
|
||||
**Using configuration array:**
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = [
|
||||
'...',
|
||||
'schema' => Adldap\Schemas\OpenLDAP::class
|
||||
];
|
||||
|
||||
$ad->addProvider($config);
|
||||
```
|
||||
|
||||
**Using configuration object:**
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = new Adldap\Configuration\DomainConfiguration();
|
||||
|
||||
$config->set('schema', Adldap\Schemas\OpenLDAP::class);
|
||||
|
||||
$ad->addProvider($config);
|
||||
```
|
||||
|
||||
Once you've set the schema of your connection provider, you can use the same API interacting with different LDAP servers.
|
||||
|
||||
Continue onto the [searching](searching.md) documentation to learn how to begin querying your LDAP server(s).
|
||||
|
||||
## Using G-Suite Secure LDAP Service
|
||||
|
||||
G-Suite LDAP service only uses client certificates and no username + password, make sure yo match base_dn with your domian.
|
||||
|
||||
```php
|
||||
$ad = new \Adldap\Adldap();
|
||||
|
||||
// Create a configuration array.
|
||||
$config = [
|
||||
'hosts' => ['ldap.google.com'],
|
||||
'base_dn' => 'dc=your-domain,dc=com',
|
||||
'use_tls' => true,
|
||||
'version' => 3,
|
||||
'schema' => Adldap\Schemas\GSuite::class,
|
||||
'custom_options' => [
|
||||
LDAP_OPT_X_TLS_CERTFILE => 'Google_2023_02_05_35779.crt',
|
||||
LDAP_OPT_X_TLS_KEYFILE => 'Google_2023_02_05_35779.key',
|
||||
]
|
||||
];
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
try {
|
||||
$provider = $ad->connect();
|
||||
|
||||
$results = $provider->search()->ous()->get();
|
||||
|
||||
echo 'OUs:'."\r\n";
|
||||
echo '==============='."\r\n";
|
||||
foreach($results as $ou) {
|
||||
echo $ou->getDn()."\r\n";
|
||||
}
|
||||
|
||||
echo "\r\n";
|
||||
|
||||
$results = $provider->search()->users()->get();
|
||||
|
||||
echo 'Users:'."\r\n";
|
||||
echo '==============='."\r\n";
|
||||
foreach($results as $user) {
|
||||
|
||||
echo $user->getAccountName()."\r\n";
|
||||
}
|
||||
|
||||
echo "\r\n";
|
||||
|
||||
$results = $provider->search()->groups()->get();
|
||||
|
||||
echo 'Groups:'."\r\n";
|
||||
echo '==============='."\r\n";
|
||||
foreach($results as $group) {
|
||||
echo $group->getCommonName().' | '.$group->getDisplayName()."\r\n";
|
||||
}
|
||||
|
||||
} catch (\Adldap\Auth\BindException $e) {
|
||||
|
||||
echo 'Error: '.$e->getMessage()."\r\n";
|
||||
}
|
||||
```
|
||||
|
||||
## Raw Operations
|
||||
|
||||
### Introduction
|
||||
|
||||
If you want to connect to your LDAP server without utilizing Adldap's models (old fashion way), and want to get back the data in a raw format you can easily do so.
|
||||
|
||||
If you call `getConnection()` on your connected provider instance, you can perform all LDAP functions on a container class that encapsulates all of PHP's LDAP methods.
|
||||
|
||||
You can view all methods avaialble by browsing the LDAP class [here](https://github.com/Adldap2/Adldap2/blob/master/src/Connections/Ldap.php).
|
||||
|
||||
Now for some examples:
|
||||
|
||||
### Examples
|
||||
|
||||
```php
|
||||
$ad = new Adldap\Adldap();
|
||||
|
||||
$config = ['...'];
|
||||
|
||||
$ad->addProvider($config);
|
||||
|
||||
$provider = $ad->connect();
|
||||
|
||||
$rawConnection = $provider->getConnection();
|
||||
|
||||
// Performing a raw search.
|
||||
$result = $rawConnection->search($basedn = 'dc=corp,dc=acme,dc=org', $filter = "cn=johndoe", $selectedAttributes = ['cn', 'department']);
|
||||
|
||||
$dn = "cn=John Smith,ou=Wizards,dc=example,dc=com";
|
||||
|
||||
// Adding a new LDAP record.
|
||||
$result = $rawConnection->add($dn, $entry);
|
||||
|
||||
// Batch modifying an LDAP record.
|
||||
$modifs = [
|
||||
[
|
||||
"attrib" => "telephoneNumber",
|
||||
"modtype" => LDAP_MODIFY_BATCH_ADD,
|
||||
"values" => ["+1 555 555 1717"],
|
||||
],
|
||||
];
|
||||
|
||||
$result = $rawConnection->modifyBatch($dn, $modifs);
|
||||
|
||||
// Deleting an LDAP record.
|
||||
$result = $rawConnection->delete($dn);
|
||||
|
||||
// .. etc
|
||||
```
|
122
data/web/inc/lib/vendor/adldap2/adldap2/docs/troubleshooting.md
vendored
Normal file
122
data/web/inc/lib/vendor/adldap2/adldap2/docs/troubleshooting.md
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
# Troubleshooting
|
||||
|
||||
#### Creating and Setting a Users Password
|
||||
|
||||
To set a users password when you've created a new one, you need to enable their account, **then** set their password.
|
||||
|
||||
For example:
|
||||
|
||||
```php
|
||||
// Construct a new user instance.
|
||||
$user = $provider->make()->user();
|
||||
|
||||
// Set the user profile details.
|
||||
$user->setAccountName('jdoe');
|
||||
$user->setFirstName('John');
|
||||
$user->setLastName('Doe');
|
||||
$user->setCompany('ACME');
|
||||
$user->setEmail('jdoe@acme.com');
|
||||
|
||||
// Save the new user.
|
||||
if ($user->save()) {
|
||||
// Enable the new user (using user account control).
|
||||
$user->setUserAccountControl(512);
|
||||
|
||||
// Set new user password
|
||||
$user->setPassword('Password123');
|
||||
|
||||
// Save the user.
|
||||
if($user->save()) {
|
||||
// The password was saved successfully.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Determining and Troubleshooting a Binding Failure
|
||||
|
||||
> **Note**: The below guide is using ActiveDirectory. Your mileage will vary using other LDAP distributions.
|
||||
|
||||
To determine the reason why a bind attempt failed, you can use the event dispatcher to listen for
|
||||
the `Failed` event, and retrieve the errors that were returned from your LDAP server:
|
||||
|
||||
```php
|
||||
use Adldap\Adldap;
|
||||
use Adldap\Auth\Events\Failed;
|
||||
|
||||
$d = Adldap::getEventDispatcher();
|
||||
|
||||
$d->listen(Failed::class, function (Failed $event) {
|
||||
$conn = $event->connection;
|
||||
|
||||
echo $conn->getLastError(); // 'Invalid credentials'
|
||||
echo $conn->getDiagnosticMessage(); // '80090308: LdapErr: DSID-0C09042A, comment: AcceptSecurityContext error, data 532, v3839'
|
||||
|
||||
if ($error = $conn->getDetailedError()) {
|
||||
$error->getErrorCode(); // 49
|
||||
$error->getErrorMessage(); // 'Invalid credentials'
|
||||
$error->getDiagnosticMessage(); // '80090308: LdapErr: DSID-0C09042A, comment: AcceptSecurityContext error, data 532, v3839'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The above diagnostic message can be parsed down further if needed. The error code after the 'data' string
|
||||
in the above message indicates several things about the bind failure. Here is a list:
|
||||
|
||||
- 525 - user not found
|
||||
- 52e - invalid credentials
|
||||
- 530 - not permitted to logon at this time
|
||||
- 531 - not permitted to logon at this workstation
|
||||
- 532 - password expired
|
||||
- 533 - account disabled
|
||||
- 701 - account expired
|
||||
- 773 - user must reset password
|
||||
- 775 - user account locked
|
||||
|
||||
From the example above, you can see that the authenticating account has their password expired, due to "532" error code.
|
||||
|
||||
#### Retrieving All Records Inside a Group
|
||||
|
||||
To retrieve all records inside a particular group (including nested groups), use the `rawFilter()` method:
|
||||
|
||||
```php
|
||||
// The `memberof:1.2.840.113556.1.4.1941:` string indicates
|
||||
// that we want all nested group records as well.
|
||||
$filter = '(memberof:1.2.840.113556.1.4.1941:=CN=MyGroup,DC=example,DC=com)';
|
||||
|
||||
$users = $provider->search()->rawFilter($filter)->get();
|
||||
```
|
||||
|
||||
#### I'm connected but not getting any search results!
|
||||
|
||||
The first thing you need to ensure is your `base_dn` in your configuration.
|
||||
|
||||
Your `base_dn` needs to identical to the base DN on your domain. Even one mistyped character will result in no search results.
|
||||
|
||||
If you also include an `ou` in your base DN (ex. `ou=Accounting,dc=corp,dc=acme,dc=org`), you will only receive results inside the `Accounting` OU.
|
||||
|
||||
Once you're connected to your LDAP server, retrieve the Root DSE record.
|
||||
|
||||
Here's a full example:
|
||||
|
||||
```php
|
||||
$providers = [
|
||||
'default' => [
|
||||
'base_dn' => '',
|
||||
'...',
|
||||
]
|
||||
];
|
||||
|
||||
$ad = new Adldap\Adldap($providers);
|
||||
|
||||
try {
|
||||
$provider = $ad->connect();
|
||||
|
||||
$root = $provider->search()->getRootDse();
|
||||
|
||||
// ex. Returns 'dc=corp,dc=acme,dc=org'
|
||||
die($root->getRootDomainNamingContext());
|
||||
|
||||
} catch (Adldap\Auth\BindException $e) {
|
||||
//
|
||||
}
|
||||
```
|
8
data/web/inc/lib/vendor/adldap2/adldap2/license.md
vendored
Normal file
8
data/web/inc/lib/vendor/adldap2/adldap2/license.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
The MIT License (MIT)
|
||||
Copyright © Steve Bauman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
data/web/inc/lib/vendor/adldap2/adldap2/phpunit.xml
vendored
Normal file
22
data/web/inc/lib/vendor/adldap2/adldap2/phpunit.xml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Adldap2 Test Suite">
|
||||
<directory suffix="Test.php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
47
data/web/inc/lib/vendor/adldap2/adldap2/readme.md
vendored
Normal file
47
data/web/inc/lib/vendor/adldap2/adldap2/readme.md
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<p align="center">
|
||||
<strong>:wave: Hey there! Looking for something even easier to use for LDAP integration in your PHP applications?</strong>
|
||||
</br>
|
||||
<h3 align="center">
|
||||
🎉 Introducing <a href="https://github.com/DirectoryTree/LdapRecord" target="_blank" title="LdapRecord GitHub Repository">LdapRecord</a> 🎉
|
||||
</h3>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>
|
||||
<a href="https://ldaprecord.com">LdapRecord</a> is the successor to Adldap2 - and comes with a ton of new features.
|
||||
</strong> </br> Adldap2 will continue to be supported with bug fixes, <i>but will not receive new features.</i>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>
|
||||
<a href="https://stevebauman.ca/why-ldap-record/">Read Why</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h1 align="center">Adldap2</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/Adldap2/Adldap2"><img src="https://img.shields.io/travis/Adldap2/Adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://scrutinizer-ci.com/g/Adldap2/Adldap2/?branch=master"><img src="https://img.shields.io/scrutinizer/g/adLDAP2/adLDAP2/master.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/dt/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/v/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/l/adldap2/adldap2.svg?style=flat-square"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Adldap2 is a PHP package that provides LDAP authentication and directory management tools using the <a href="https://en.wikipedia.org/wiki/Active_record_pattern">Active Record pattern</a>.
|
||||
</p>
|
||||
|
||||
<h4 align="center">
|
||||
<a href="http://adldap2.github.io/Adldap2/#/?id=quick-start">Quickstart</a>
|
||||
<span> · </span>
|
||||
<a href="http://adldap2.github.io/Adldap2/">Documentation</a>
|
||||
</h4>
|
||||
|
||||
- **Up and running in minutes.** Effortlessly connect to your LDAP servers and start running queries & operations in a matter of minutes.
|
||||
|
||||
- **Fluent query builder.** Building LDAP queries has never been so easy. Find the records you're looking for in a couple lines or less with a fluent interface.
|
||||
|
||||
- **Supercharged Active Record.** Create and modify LDAP records with ease. All LDAP records are individual models. Simply modify the attributes on the model and save it to persist the changes to your LDAP server.
|
194
data/web/inc/lib/vendor/adldap2/adldap2/src/Adldap.php
vendored
Normal file
194
data/web/inc/lib/vendor/adldap2/adldap2/src/Adldap.php
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace Adldap;
|
||||
|
||||
use Adldap\Log\EventLogger;
|
||||
use Adldap\Connections\Ldap;
|
||||
use InvalidArgumentException;
|
||||
use Adldap\Log\LogsInformation;
|
||||
use Adldap\Connections\Provider;
|
||||
use Adldap\Events\DispatchesEvents;
|
||||
use Adldap\Connections\ProviderInterface;
|
||||
use Adldap\Connections\ConnectionInterface;
|
||||
use Adldap\Configuration\DomainConfiguration;
|
||||
|
||||
class Adldap implements AdldapInterface
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use LogsInformation;
|
||||
/**
|
||||
* The default provider name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $default = 'default';
|
||||
|
||||
/**
|
||||
* The connection providers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providers = [];
|
||||
|
||||
/**
|
||||
* The events to register listeners for during initialization.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
'Adldap\Auth\Events\*',
|
||||
'Adldap\Query\Events\*',
|
||||
'Adldap\Models\Events\*',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $providers = [])
|
||||
{
|
||||
foreach ($providers as $name => $config) {
|
||||
$this->addProvider($config, $name);
|
||||
}
|
||||
|
||||
if ($default = key($providers)) {
|
||||
$this->setDefaultProvider($default);
|
||||
}
|
||||
|
||||
$this->initEventLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addProvider($config, $name = 'default', ConnectionInterface $connection = null)
|
||||
{
|
||||
if ($this->isValidConfig($config)) {
|
||||
$config = new Provider($config, $connection ?? new Ldap($name));
|
||||
}
|
||||
|
||||
if ($config instanceof ProviderInterface) {
|
||||
$this->providers[$name] = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(
|
||||
"You must provide a configuration array or an instance of Adldap\Connections\ProviderInterface."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given config is valid.
|
||||
*
|
||||
* @param mixed $config
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValidConfig($config)
|
||||
{
|
||||
return is_array($config) || $config instanceof DomainConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProviders()
|
||||
{
|
||||
return $this->providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProvider($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->providers)) {
|
||||
return $this->providers[$name];
|
||||
}
|
||||
|
||||
throw new AdldapException("The connection provider '$name' does not exist.");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDefaultProvider($name = 'default')
|
||||
{
|
||||
if ($this->getProvider($name) instanceof ProviderInterface) {
|
||||
$this->default = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultProvider()
|
||||
{
|
||||
return $this->getProvider($this->default);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeProvider($name)
|
||||
{
|
||||
unset($this->providers[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function connect($name = null, $username = null, $password = null)
|
||||
{
|
||||
$provider = $name ? $this->getProvider($name) : $this->getDefaultProvider();
|
||||
|
||||
return $provider->connect($username, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$provider = $this->getDefaultProvider();
|
||||
|
||||
if (! $provider->getConnection()->isBound()) {
|
||||
$provider->connect();
|
||||
}
|
||||
|
||||
return call_user_func_array([$provider, $method], $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the event logger.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initEventLogger()
|
||||
{
|
||||
$dispatcher = static::getEventDispatcher();
|
||||
|
||||
$logger = $this->newEventLogger();
|
||||
|
||||
// We will go through each of our event wildcards and register their listener.
|
||||
foreach ($this->listen as $event) {
|
||||
$dispatcher->listen($event, function ($eventName, $events) use ($logger) {
|
||||
foreach ($events as $event) {
|
||||
$logger->log($event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new event logger instance.
|
||||
*
|
||||
* @return EventLogger
|
||||
*/
|
||||
protected function newEventLogger()
|
||||
{
|
||||
return new EventLogger(static::getLogger());
|
||||
}
|
||||
}
|
8
data/web/inc/lib/vendor/adldap2/adldap2/src/AdldapException.php
vendored
Normal file
8
data/web/inc/lib/vendor/adldap2/adldap2/src/AdldapException.php
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Adldap;
|
||||
|
||||
class AdldapException extends \Exception
|
||||
{
|
||||
//
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user