Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#680] Add support to get groups for users from secondary domain #681

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
fail-fast: false
matrix:
container:
- alpine:3.14
- alpine:3.12
- alpine:3.16
- amazonlinux:2018.03
- amazonlinux:2
- amazonlinux:2022
Expand All @@ -49,8 +50,9 @@ jobs:
- centos:7
- centos:8.2.2004
- oraclelinux:8
- rockylinux:9
- ubuntu:14.04
- ubuntu:16.04
- ubuntu:18.04
- ubuntu:22.04

# ubuntu-latest is GitHub's newest well-suported Linux distro.
Expand Down Expand Up @@ -81,12 +83,12 @@ jobs:
sed -i s@^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever/@baseurl=https://vault.centos.org/8.2.2004/@ /etc/yum.repos.d/*.repo
yum -y upgrade

- name: Amazon Linux 2022 setup
if: matrix.container == 'amazonlinux:2022'
- name: Install libxcrypt-compat on latest distros
if: matrix.container == 'amazonlinux:2022' || matrix.container == 'rockylinux:9'
run: yum -y install libxcrypt-compat

- name: Yum-based setup
if: startsWith(matrix.container, 'centos') || startsWith(matrix.container, 'amazon') || startsWith(matrix.container, 'oracle')
if: startsWith(matrix.container, 'centos') || startsWith(matrix.container, 'amazon') || startsWith(matrix.container, 'oracle') || startsWith(matrix.container, 'rocky')
run: yum -y install git tar which sudo

- name: Ubuntu setup
Expand Down
2 changes: 1 addition & 1 deletion brink.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
BASE_REQUIREMENTS='pip==20.3.4chevah chevah-brink==0.79.0 paver==1.2.4'
PYTHON_CONFIGURATION='default@2.7.18.93dc340'
PYTHON_CONFIGURATION='default@2.7.18.90dc4a6'
# For production packages there are 2 options:
BINARY_DIST_URI='https://github.com/chevah/python-package/releases/download'
#BINARY_DIST_URI='https://bin.chevah.com:20443/production'
Expand Down
138 changes: 93 additions & 45 deletions brink.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
# command used to execute Python inside the newly virtual environment.
#

# Script initialization.
set -o nounset
set -o errexit
set -o pipefail
# Bash checks
set -o nounset # always check if variables exist
set -o errexit # always exit on error
set -o errtrace # trap errors in functions as well
set -o pipefail # don't ignore exit codes when piping output

# Initialize default value.
COMMAND=${1-''}
Expand Down Expand Up @@ -540,7 +541,7 @@ install_dependencies(){
# If it's too old, exit with a nice informative message.
# If it's supported, return through eval the version numbers to be used for
# naming the package, for example: '8' for RHEL 8.2, '2004' for Ubuntu 20.04,
# '314' for Alpine Linux 3.14, '71' for AIX 7.1, '114' for Solaris 11.4.
# '71' for AIX 7.1, '114' for Solaris 11.4.
#
check_os_version() {
# First parameter should be the human-readable name for the current OS.
Expand Down Expand Up @@ -588,7 +589,7 @@ check_os_version() {
if [ "$OS" = "Linux" ]; then
# For old and/or unsupported Linux distros there's a second chance!
(>&2 echo "the generic Linux runtime is used, if possible.")
check_linux_glibc
check_linux_libc
else
(>&2 echo "there is currently no support.")
exit 13
Expand All @@ -601,16 +602,42 @@ check_os_version() {

#
# For old unsupported Linux distros (some with no /etc/os-release) and for other
# unsupported Linux distros (eg. Arch), we check if the system is glibc-based.
# unsupported Linux distros, we check if the system is based on glibc or musl.
# If so, we use a generic code path that builds everything statically,
# including OpenSSL, thus only requiring glibc 2.X, where X differs by arch.
# including OpenSSL, thus only requiring glibc or musl.
#
check_linux_glibc() {
check_linux_libc() {
local ldd_output_file=".chevah_libc_version"
set +o errexit

command -v ldd > /dev/null
if [ $? -ne 0 ]; then
(>&2 echo "No ldd binary found, can't check for glibc!")
exit 18
fi

ldd --version > $ldd_output_file 2>&1
egrep "GNU\ libc|GLIBC" $ldd_output_file > /dev/null
if [ $? -eq 0 ]; then
check_glibc_version
else
egrep ^"musl\ libc" $ldd_output_file > /dev/null
if [ $? -eq 0 ]; then
check_musl_version
else
(>&2 echo "Unknown libc reported by ldd... Unsupported Linux.")
rm $ldd_output_file
exit 19
fi
fi

set -o errexit
}

check_glibc_version(){
local glibc_version
local glibc_version_array
local supported_glibc2_version
# Output to a file to avoid "write error: Broken pipe" with grep/head.
local ldd_output_file=".chevah_glibc_version"

# Supported minimum minor glibc 2.X versions for various arches.
# For x64, we build on CentOS 5.11 (Final) with glibc 2.5.
Expand All @@ -632,21 +659,6 @@ check_linux_glibc() {
echo "No specific runtime for the current distribution / version / arch."
echo "Minimum glibc version for this arch: 2.${supported_glibc2_version}."

set +o errexit

command -v ldd > /dev/null
if [ $? -ne 0 ]; then
(>&2 echo "No ldd binary found, can't check for glibc!")
exit 18
fi

ldd --version > $ldd_output_file
egrep "GNU\ libc|GLIBC" $ldd_output_file > /dev/null
if [ $? -ne 0 ]; then
(>&2 echo "No glibc reported by ldd... Unsupported Linux libc?")
exit 19
fi

# Tested with glibc 2.5/2.11.3/2.12/2.23/2.28-31 and eglibc 2.13/2.19.
glibc_version=$(head -n 1 $ldd_output_file | rev | cut -d\ -f1 | rev)
rm $ldd_output_file
Expand All @@ -672,22 +684,59 @@ check_linux_glibc() {
echo "All is good. Detected glibc version: ${glibc_version}."
fi

set -o errexit

# glibc 2 detected, we set $OS for a generic Linux build.
# Supported glibc version detected, set $OS for a generic glibc Linux build.
OS="lnx"
}

check_musl_version(){
local musl_version
local musl_version_array
local supported_musl11_version=24

echo "No specific runtime for the current distribution / version / arch."
echo "Minimum musl version for this arch: 1.1.${supported_musl11_version}."

# Tested with musl 1.1.24/1.2.2.
musl_version=$(egrep ^Version $ldd_output_file | cut -d\ -f2)
rm $ldd_output_file

if [[ $musl_version =~ [^[:digit:]\.] ]]; then
(>&2 echo "Musl version should only have numbers and periods, but:")
(>&2 echo " \$musl_version=$musl_version")
exit 25
fi

IFS=. read -a musl_version_array <<< "$musl_version"

if [ ${musl_version_array[0]} -lt 1 -o ${musl_version_array[1]} -lt 1 ];then
(>&2 echo "Only musl 1.1 or greater supported! Detected: $musl_version")
exit 26
fi

# Decrement supported_musl11_version if building against an older musl.
if [ ${musl_version_array[0]} -eq 1 -a ${musl_version_array[1]} -eq 1 \
-a ${musl_version_array[2]} -lt ${supported_musl11_version} ]; then
(>&2 echo "NOT good. Detected version is older: ${musl_version}!")
exit 27
else
echo "All is good. Detected musl version: ${musl_version}."
fi

# Supported musl version detected, set $OS for a generic musl Linux build.
OS="lnx_musl"
}

#
# For glibc-based Linux distros, after checking if current version is
# supported with check_os_version(), $OS might already be set to "lnx"
# if current version is too old, through check_linux_glibc().
# For Linux distros with a supported libc, after checking if current version is
# supported with check_os_version(), $OS might be set to something like "lnx"
# if current version is too old, through check_linux_libc() and its subroutines.
#
set_os_if_not_generic() {
local distro_name="$1"
local distro_version="$2"

if [ "$OS" != "lnx" ]; then
# Check if OS starts with "lnx", to match "lnx_musl" too, just in case.
if [ "${OS#lnx}" = "$OS" ]; then
OS="${distro_name}${distro_version}"
fi
}
Expand All @@ -709,19 +758,24 @@ detect_os() {
if [ ! -f /etc/os-release ]; then
# No /etc/os-release file present, so we don't support this
# distro, but check for glibc, the generic build should work.
check_linux_glibc
check_linux_libc
else
source /etc/os-release
linux_distro="$ID"
distro_fancy_name="$NAME"
# Some rolling-release distros (eg. Arch Linux) have
# no VERSION_ID here, so don't count on it unconditionally.
case "$linux_distro" in
rhel|centos|ol)
rhel|centos|almalinux|rocky|ol)
os_version_raw="$VERSION_ID"
check_os_version "Red Hat Enterprise Linux" 8 \
"$os_version_raw" os_version_chevah
set_os_if_not_generic "rhel" $os_version_chevah
if [ ${os_version_chevah} == "8" ]; then
set_os_if_not_generic "rhel" $os_version_chevah
else
# OpenSSL 3.0.x not supported by cryptography 3.3.x.
check_linux_libc
fi
;;
ubuntu|ubuntu-core)
os_version_raw="$VERSION_ID"
Expand All @@ -732,23 +786,17 @@ detect_os() {
# 04 or first two digits are uneven, use generic build.
if [ ${os_version_chevah%%04} == ${os_version_chevah} \
-o $(( ${os_version_chevah:0:2} % 2 )) -ne 0 ]; then
check_linux_glibc
check_linux_libc
elif [ ${os_version_chevah} == "2204" ]; then
# OpenSSL 3.0.x not supported by cryptography 3.3.x.
check_linux_glibc
check_linux_libc
fi
set_os_if_not_generic "ubuntu" $os_version_chevah
;;
alpine)
os_version_raw="$VERSION_ID"
check_os_version "$distro_fancy_name" 3.12 \
"$os_version_raw" os_version_chevah
set_os_if_not_generic "alpine" $os_version_chevah
;;
*)
# Supported distros with unsupported OpenSSL versions or
# distros not specifically supported: SLES, Debian, etc.
check_linux_glibc
check_linux_libc
;;
esac
fi
Expand Down
35 changes: 22 additions & 13 deletions chevah/compat/nt_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,13 @@ def _createLocalProfile(self, username, token):
Create the local profile for specified `username`.
"""
try:
primary_domain_controller, name = self._parseUPN(username)
with self.executeAsUser(username, token):
# We need to run as the user, for the case in which the
# user in not in the primary domain.
primary_domain_controller, name = self._parseUPN(username)

user_info_4 = win32net.NetUserGetInfo(
primary_domain_controller, name, 4)
user_info_4 = win32net.NetUserGetInfo(
primary_domain_controller, name, 4)

profile_path = user_info_4['profile']
# LoadUserProfile doesn't like an empty string.
Expand Down Expand Up @@ -200,17 +203,23 @@ def getGroupForUser(self, username, groups, token):
if not groups:
raise ValueError('Groups for validation can\'t be empty.')

primary_domain_controller, name = self._parseUPN(username)
with self.executeAsUser(username, token):
# We run these operations as the user, for the case in which the
# user is in secondary domain.
# Here `primary_domain_controller` can be the primary domain for the
# secondary domain :)
primary_domain_controller, name = self._parseUPN(username)

for group in groups:
try:
group_sid, group_domain, group_type = (
win32security.LookupAccountName(
primary_domain_controller, group))
except (win32security.error, pywintypes.error):
continue
if win32security.CheckTokenMembership(token, group_sid):
return group

for group in groups:
try:
group_sid, group_domain, group_type = (
win32security.LookupAccountName(
primary_domain_controller, group))
except (win32security.error, pywintypes.error):
continue
if win32security.CheckTokenMembership(token, group_sid):
return group
return None

def authenticateWithUsernameAndPassword(self, username, password):
Expand Down
5 changes: 5 additions & 0 deletions release-notes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Release notes for chevah.compat
===============================

0.64.4 - 2022-10-17
-------------------

* The `getGroupForUser` was fixed to work with secondary domains.


0.64.3 - 2022-09-14
-------------------
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import Command, find_packages, setup
import os

VERSION = '0.64.3'
VERSION = '0.64.4'


class PublishCommand(Command):
Expand Down