From 853ea853173bdd8b6c9a5282518e82a80b8b4c3c Mon Sep 17 00:00:00 2001 From: bernhard Date: Sat, 15 Feb 2025 10:00:00 +0100 Subject: [PATCH 1/4] Issue #3448: remove the workflow docker_image_update_checker.yml replaced by docker_image_update_checker.yml --- .../workflows/docker_image_update_checker.yml | 172 ------------------ 1 file changed, 172 deletions(-) delete mode 100644 .github/workflows/docker_image_update_checker.yml diff --git a/.github/workflows/docker_image_update_checker.yml b/.github/workflows/docker_image_update_checker.yml deleted file mode 100644 index 4aa0c0b795..0000000000 --- a/.github/workflows/docker_image_update_checker.yml +++ /dev/null @@ -1,172 +0,0 @@ -%YAML 1.1 ---- -name: 'DockerImageUpdateChecker' -# Adapted from https://github.com/marketplace/actions/docker-image-update-checker#minimal - -# TODO: check the relevant tags in rel-10_0, rel-10_1, rel-11_0 and trigger rebuilds in these commits -# TODO: saner setup which branch uses which base image - -on: - - # The trigger on 'workflow_dispatch' allows manual start - # on https://github.com/RotherOSS/otobo/actions/workflows/docker_image_update_checker.yml - workflow_dispatch: - - # The trigger on 'schedule' allows to run daily. Time is in UTC declared in cron syntax. - # The scheduled jobs run only on the default branch. - schedule: - - cron: '37 2 * * *' - -jobs: - CheckDockerImageUpdate: - strategy: - - # create different images - # note that there is no release build for the otobo-web-kerberos target - matrix: - target: [ 'otobo-web', 'otobo-elasticsearch', 'otobo-nginx-webproxy', 'otobo-nginx-kerberos-webproxy', 'otobo-selenium-chrome' ] - patch: [ '11_0_1', '11_0_2', '11_0_3', '11_0_4', '11_0_5', '11_0_6' ] - include: - - - target: 'otobo-web' - dockerfile: 'otobo.web.dockerfile' - context: '.' - repository: 'rotheross/otobo' - base_image: 'perl:5.38-bookworm' - - - target: 'otobo-elasticsearch' - dockerfile: 'otobo.elasticsearch.dockerfile' - context: 'scripts/elasticsearch' - repository: 'rotheross/otobo-elasticsearch' - base_image: 'elasticsearch:7.17.3' - - - target: 'otobo-nginx-webproxy' - dockerfile: 'otobo.nginx.dockerfile' - context: 'scripts/nginx' - repository: 'rotheross/otobo-nginx-webproxy' - base_image: 'nginx:mainline' - - - target: 'otobo-nginx-kerberos-webproxy' - dockerfile: 'otobo.nginx.dockerfile' - context: 'scripts/nginx' - repository: 'rotheross/otobo-nginx-kerberos-webproxy' - base_image: 'nginx:mainline' - - - target: 'otobo-selenium-chrome' - dockerfile: 'otobo.selenium-chrome.dockerfile' - context: 'scripts/test/sample' - repository: 'rotheross/otobo-selenium-chrome' - base_image: 'selenium/standalone-chrome-debug:3.141.59-20210422' - - runs-on: ${{ matrix.target }} - steps: - - - name: Setting up the environment file - run: | - patch=${{ matrix.patch }} - docker_tag="rel-${patch}" - mixed_case_repository="${{ github.repository }}" - lowercased_repository="${mixed_case_repository,,}" - build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ') - ( - echo "otobo_branch=rel-${patch}" - echo "otobo_base_image=${{ matrix.base_image }}" - echo "otobo_docker_tag=${docker_tag}" - echo "otobo_image=${lowercased_repository}:${docker_tag}" - echo "otobo_build_date=${build_date}" - ) >> $GITHUB_ENV - - - - # this step sets ${{ steps.check.outputs.needs-updating }} - name: Check whether base image was updated - id: check - uses: lucacome/docker-image-update-checker@v1 - with: - base-image: ${{ env.otobo_base_image }} - image: ${{ env.otobo_image }} - - - - # print the result in any case - name: Report the check result - run: | - echo "The OTOBO web image needs updating: ${{ steps.check.outputs.needs-updating }}" - - - - name: Set up Docker Buildx - if: steps.check.outputs.needs-updating == 'true' - uses: docker/setup-buildx-action@v3 - - - - name: 'check out the relevant OTOBO branch' - if: steps.check.outputs.needs-updating == 'true' - uses: actions/checkout@v4 - with: - ref: ${{ env.otobo_branch }} - - - - # needed for build arg GIT_COMMIT - # can't use github.sha here as we need the commit of the checked out branch - name: 'get the commit SHA of the current checkout' - if: steps.check.outputs.needs-updating == 'true' - run: echo "otobo_commit=$(git log -1 '--format=format:%H')" >> $GITHUB_ENV - - - - # build the image, not pushing yet, no pushing as DockerHub access is not set up yet - # Caching with Github Actions Cache, limited to 10 GB - # context: . indicates that the current checkout is used - name: Build - if: steps.check.outputs.needs-updating == 'true' - uses: docker/build-push-action@v6 - with: - load: true - context: ${{ matrix.context }} - file: ${{ matrix.dockerfile }} - pull: true - build-args: | - BUILD_DATE=${{ env.otobo_build_date }} - DOCKER_TAG=${{ env.otobo_docker_tag }} - GIT_REPO=${{ github.repositoryUrl }} - GIT_BRANCH=${{ env.otobo_branch }} - GIT_COMMIT=${{ env.otobo_commit }} - target: ${{ matrix.target }} - tags: ${{ env.otobo_image }} - cache-from: type=gha - cache-to: type=gha,mode=max` - - - - # otobo_first_time hasn't run yet, so /opt/otobo is still empty - name: Info - if: ${{ steps.check.outputs.needs-updating == 'true' && matrix.target == 'otobo-web' }} - run: | - docker run --rm -w /opt/otobo_install/otobo_next --entrypoint /bin/bash $otobo_image -c "more git-repo.txt git-branch.txt git-commit.txt RELEASE | cat" - - - - # login to Docker Hub only after the build - name: Login to Docker Hub - if: steps.check.outputs.needs-updating == 'true' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - - # finally upload to DockerHub - # the built image is already available in the job - name: Push to DockerHub - if: steps.check.outputs.needs-updating == 'true' - uses: docker/build-push-action@v6 - with: - push: true - context: ${{ matrix.context }} - file: ${{ matrix.dockerfile }} - pull: true - build-args: | - BUILD_DATE=${{ env.otobo_build_date }} - DOCKER_TAG=${{ env.otobo_docker_tag }} - GIT_REPO=${{ github.repositoryUrl }} - GIT_BRANCH=${{ env.otobo_branch }} - GIT_COMMIT=${{ env.otobo_commit }} - target: ${{ matrix.target }} - tags: ${{ env.otobo_image }} - cache-from: type=gha - cache-to: type=gha,mode=max From c4ec80d6e4c0746e5355689b5e55caece84a5e9b Mon Sep 17 00:00:00 2001 From: bernhard Date: Mon, 10 Feb 2025 11:16:05 +0100 Subject: [PATCH 2/4] Issue #4153: make the two SetPassword() methods more similar These two methods are in Kernel::System::User and in Kernel::System::CustomerUser::DB. They basically do the same hashification of the passed in password but have superficial diff. Saintainance is easier when the methods look the same. A significant difference is that Kernel::System::CustomerUser::DB::SetPassword() sets the utf8 flag on the hash value. It is believed that this actually makes no difference as the hashes consists of only low byte iso8859 characters. Also improve some of the code comments. --- Kernel/System/CustomerUser/DB.pm | 39 ++++++++++-------- Kernel/System/User.pm | 69 ++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Kernel/System/CustomerUser/DB.pm b/Kernel/System/CustomerUser/DB.pm index 4d4e64099a..a85056653e 100644 --- a/Kernel/System/CustomerUser/DB.pm +++ b/Kernel/System/CustomerUser/DB.pm @@ -23,7 +23,7 @@ use warnings; use Digest::SHA (); # CPAN modules -use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt ); +use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt); # OTOBO modules use Kernel::System::VariableCheck qw(:all); @@ -50,8 +50,7 @@ sub new { my ( $Type, %Param ) = @_; # allocate new hash for object - my $Self = {}; - bless( $Self, $Type ); + my $Self = bless {}, $Type; # check needed data for my $Needed (qw( PreferencesObject CustomerUserMap )) { @@ -1672,8 +1671,7 @@ sub CustomerUserUpdate { sub SetPassword { my ( $Self, %Param ) = @_; - my $Login = $Param{UserLogin}; - my $Pw = $Param{PW} || ''; + # This method is similar to Kernel::System::User::SetPassword() # check ro/rw if ( $Self->{ReadOnly} ) { @@ -1681,24 +1679,32 @@ sub SetPassword { Priority => 'error', Message => 'Customer backend is read only!', ); + return; } + my $Login = $Param{UserLogin}; + my $Pw = $Param{PW} || ''; + # check needed stuff - if ( !$Param{UserLogin} ) { + if ( !$Login ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Need UserLogin!', ); + return; } + + # TODO: add check whether the CustomerUser exists + my $CryptedPw = ''; - my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); + my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); + my $ConfigSection = 'Customer::AuthModule::DB'; - my $CryptType = $ConfigObject->Get('Customer::AuthModule::DB::CryptType') || 'sha2'; + my $CryptType = $ConfigObject->Get("${ConfigSection}::CryptType") || 'sha2'; - # get encode object my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode'); # crypt plain (no crypt at all) @@ -1706,7 +1712,7 @@ sub SetPassword { $CryptedPw = $Pw; } - # crypt with unix crypt + # crypt with UNIX crypt elsif ( $CryptType eq 'crypt' ) { # encode output, needed by crypt() only non utf8 signs @@ -1717,7 +1723,7 @@ sub SetPassword { $EncodeObject->EncodeInput( \$CryptedPw ); } - # crypt with md5 crypt + # crypt with unix_md5_crypt elsif ( $CryptType eq 'md5' || !$CryptType ) { # encode output, needed by unix_md5_crypt() only non utf8 signs @@ -1728,7 +1734,7 @@ sub SetPassword { $EncodeObject->EncodeInput( \$CryptedPw ); } - # crypt with md5 crypt (compatible with Apache's .htpasswd files) + # crypt with md5 (compatible with Apache's .htpasswd files) elsif ( $CryptType eq 'apr1' ) { # encode output, needed by apache_md5_crypt() only non utf8 signs @@ -1748,6 +1754,7 @@ sub SetPassword { $CryptedPw = $SHAObject->hexdigest(); } + # crypt with sha512 elsif ( $CryptType eq 'sha512' ) { my $SHAObject = Digest::SHA->new('sha512'); @@ -1759,19 +1766,17 @@ sub SetPassword { # bcrypt elsif ( $CryptType eq 'bcrypt' ) { - # get main object my $MainObject = $Kernel::OM->Get('Kernel::System::Main'); if ( !$MainObject->Require('Crypt::Eksblowfish::Bcrypt') ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', - Message => - "CustomerUser: '$Login' tried to store password with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", + Message => "CustomerUser: '$Login' tried to store password with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", ); return; } - my $Cost = $ConfigObject->Get('Customer::AuthModule::DB::bcryptCost') // 12; + my $Cost = $ConfigObject->Get("${ConfigSection}::bcryptCost") // 12; # Don't allow values smaller than 9 for security. $Cost = 9 if $Cost < 9; @@ -1799,7 +1804,7 @@ sub SetPassword { $CryptedPw = "BCRYPT:$Cost:$Salt:" . Crypt::Eksblowfish::Bcrypt::en_base64($Octets); } - # crypt with sha2 as fallback + # crypt with sha256 as fallback else { my $SHAObject = Digest::SHA->new('sha256'); diff --git a/Kernel/System/User.pm b/Kernel/System/User.pm index 23dcd8ab4e..37d805dfb0 100644 --- a/Kernel/System/User.pm +++ b/Kernel/System/User.pm @@ -23,9 +23,9 @@ use warnings; use Digest::SHA (); # CPAN modules +use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt); # OTOBO modules -use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt ); our @ObjectDependencies = ( 'Kernel::Config', @@ -789,31 +789,40 @@ to set users passwords sub SetPassword { my ( $Self, %Param ) = @_; + # This method is similar to Kernel::System::CustomerUser::DB::SetPassword() + + my $Login = $Param{UserLogin}; + my $Pw = $Param{PW} || ''; + # check needed stuff - if ( !$Param{UserLogin} ) { + if ( !$Login ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', - Message => 'Need UserLogin!' + Message => 'Need UserLogin!', ); + return; } # get old user data - my %User = $Self->GetUserData( User => $Param{UserLogin} ); + my %User = $Self->GetUserData( User => $Login ); if ( !$User{UserLogin} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'No such User!', ); + return; } - my $Pw = $Param{PW} || ''; my $CryptedPw = ''; - my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); + my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); + my $ConfigSection = 'AuthModule::DB'; - my $CryptType = $ConfigObject->Get('AuthModule::DB::CryptType') || 'sha2'; + my $CryptType = $ConfigObject->Get("${ConfigSection}::CryptType") || 'sha2'; + + my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode'); # crypt plain (no crypt at all) if ( $CryptType eq 'plain' ) { @@ -824,37 +833,37 @@ sub SetPassword { elsif ( $CryptType eq 'crypt' ) { # encode output, needed by crypt() only non utf8 signs - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); + $EncodeObject->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Login ); - $CryptedPw = crypt( $Pw, $Param{UserLogin} ); + $CryptedPw = crypt( $Pw, $Login ); } - # crypt with md5 + # crypt with unix_md5_crypt elsif ( $CryptType eq 'md5' || !$CryptType ) { # encode output, needed by unix_md5_crypt() only non utf8 signs - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); + $EncodeObject->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Login ); - $CryptedPw = unix_md5_crypt( $Pw, $Param{UserLogin} ); + $CryptedPw = unix_md5_crypt( $Pw, $Login ); } # crypt with md5 (compatible with Apache's .htpasswd files) elsif ( $CryptType eq 'apr1' ) { - # encode output, needed by unix_md5_crypt() only non utf8 signs - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); + # encode output, needed by apache_md5_crypt() only non utf8 signs + $EncodeObject->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Login ); - $CryptedPw = apache_md5_crypt( $Pw, $Param{UserLogin} ); + $CryptedPw = apache_md5_crypt( $Pw, $Login ); } # crypt with sha1 elsif ( $CryptType eq 'sha1' ) { my $SHAObject = Digest::SHA->new('sha1'); - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Pw ); $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); } @@ -863,7 +872,7 @@ sub SetPassword { elsif ( $CryptType eq 'sha512' ) { my $SHAObject = Digest::SHA->new('sha512'); - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Pw ); $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); } @@ -871,16 +880,17 @@ sub SetPassword { # bcrypt elsif ( $CryptType eq 'bcrypt' ) { - if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) { + my $MainObject = $Kernel::OM->Get('Kernel::System::Main'); + + if ( !$MainObject->Require('Crypt::Eksblowfish::Bcrypt') ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', - Message => - "User: '$User{UserLogin}' tried to store password with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", + Message => "User: '$Login' tried to store password with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", ); return; } - my $Cost = $ConfigObject->Get('AuthModule::DB::bcryptCost') // 12; + my $Cost = $ConfigObject->Get("${ConfigSection}::bcryptCost") // 12; # Don't allow values smaller than 9 for security. $Cost = 9 if $Cost < 9; @@ -888,10 +898,10 @@ sub SetPassword { # Current Crypt::Eksblowfish::Bcrypt limit is 31. $Cost = 31 if $Cost > 31; - my $Salt = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString( Length => 16 ); + my $Salt = $MainObject->GenerateRandomString( Length => 16 ); # remove UTF8 flag, required by Crypt::Eksblowfish::Bcrypt - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Pw ); # calculate password hash my $Octets = Crypt::Eksblowfish::Bcrypt::bcrypt_hash( @@ -914,7 +924,7 @@ sub SetPassword { my $SHAObject = Digest::SHA->new('sha256'); # encode output, needed by sha256_hex() only non utf8 signs - $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); + $EncodeObject->EncodeOutput( \$Pw ); $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); @@ -922,7 +932,8 @@ sub SetPassword { # update db my $UserLogin = lc $Param{UserLogin}; - return if !$Kernel::OM->Get('Kernel::System::DB')->Do( + + return unless $Kernel::OM->Get('Kernel::System::DB')->Do( SQL => "UPDATE $Self->{UserTable} SET $Self->{UserTableUserPW} = ? " . " WHERE $Self->{Lower}($Self->{UserTableUser}) = ?", Bind => [ \$CryptedPw, \$UserLogin ], @@ -1218,7 +1229,7 @@ generate a random password sub GenerateRandomPassword { my ( $Self, %Param ) = @_; - # generated passwords are eight characters long by default. + # generated passwords are eight characters long by default my $Size = $Param{Size} || 8; my $Password = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString( From e859302d44c917aa5c37b139c760cda60a04e2e6 Mon Sep 17 00:00:00 2001 From: bernhard Date: Tue, 11 Feb 2025 09:51:37 +0100 Subject: [PATCH 3/4] Issue #4153: make Kernel/System/Auth/DB.pm and Kernel/System/CustomerAuth/DB.pm more similar The major difference is the EncodeInput() on the password hash. This difference was introduced in commit 48620676bfd because of German Umlaute in the login_id. --- Kernel/System/Auth/DB.pm | 19 +++++++------- Kernel/System/CustomerAuth/DB.pm | 44 ++++++++++++++++---------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Kernel/System/Auth/DB.pm b/Kernel/System/Auth/DB.pm index 1a12fee452..ad3247bca8 100644 --- a/Kernel/System/Auth/DB.pm +++ b/Kernel/System/Auth/DB.pm @@ -26,9 +26,9 @@ use warnings; use Digest::SHA (); # CPAN modules +use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt); # OTOBO modules -use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt); our @ObjectDependencies = ( 'Kernel::Config', @@ -48,7 +48,7 @@ sub new { # allocate new hash for object my $Self = bless {}, $Type; - # get config object + # get needed objects my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # get user table @@ -94,6 +94,7 @@ sub Auth { Priority => 'error', Message => "Need User!" ); + return; } @@ -103,7 +104,7 @@ sub Auth { my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $RemoteAddr = $ParamObject->RemoteAddr() || 'Got no REMOTE_ADDR env!'; my $UserID = ''; - my $GetPw = ''; + my $GetPw = ''; # the hashed password, may include salt and other settings my $Method = ''; # get database object @@ -164,7 +165,6 @@ sub Auth { $CryptedPw = unix_md5_crypt( $Pw, $Salt ); $Method = 'unix_md5_crypt'; } - } # sha256 pw @@ -190,13 +190,13 @@ sub Auth { elsif ( $GetPw =~ m{^BCRYPT:} ) { # require module, log errors if module was not found - if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) - { + if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "User: $User tried to authenticate with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", ); + return; } @@ -248,7 +248,7 @@ sub Auth { # crypt pw else { - # strip Salt only for (Extended) DES, not for any of Modular crypt's + # strip salt only for (Extended) DES, not for any of modular crypts if ( $Salt !~ /^\$\d\$/ ) { $Salt =~ s/^(..).*/$1/; } @@ -291,8 +291,7 @@ sub Auth { } # login note - elsif ( ( ($GetPw) && ($User) && ($UserID) ) && $CryptedPw eq $GetPw ) { - + elsif ( $GetPw && $User && $UserID && $CryptedPw eq $GetPw ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', Message => "User: $User authentication ok (Method: $Method, REMOTE_ADDR: $RemoteAddr).", @@ -302,7 +301,7 @@ sub Auth { } # just a note - elsif ( ($UserID) && ($GetPw) ) { + elsif ( $UserID && $GetPw ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', Message => diff --git a/Kernel/System/CustomerAuth/DB.pm b/Kernel/System/CustomerAuth/DB.pm index fb9d2d690d..eb985ec3f7 100644 --- a/Kernel/System/CustomerAuth/DB.pm +++ b/Kernel/System/CustomerAuth/DB.pm @@ -26,7 +26,7 @@ use warnings; use Digest::SHA (); # CPAN modules -use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt ); +use Crypt::PasswdMD5 qw(apache_md5_crypt unix_md5_crypt); # OTOBO modules @@ -47,10 +47,8 @@ sub new { # allocate new hash for object my $Self = bless {}, $Type; - # get database object + # get needed objects $Self->{DBObject} = $Kernel::OM->Get('Kernel::System::DB'); - - # get config object my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # config options @@ -109,6 +107,7 @@ sub Auth { Priority => 'error', Message => "Need User!" ); + return; } @@ -118,7 +117,7 @@ sub Auth { my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $RemoteAddr = $ParamObject->RemoteAddr() || 'Got no REMOTE_ADDR env!'; my $UserID = ''; - my $GetPw = ''; + my $GetPw = ''; # the hashed password, may include salt and other settings my $Method = ''; # sql query @@ -145,7 +144,7 @@ sub Auth { return; } - # get encode object + # get needed objects my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode'); # crypt given pw @@ -157,7 +156,7 @@ sub Auth { $Method = 'plain'; } - # md5 or sha pw + # md5, bcrypt or sha pw elsif ( $GetPw !~ /^.{13}$/ ) { # md5 pw @@ -191,8 +190,8 @@ sub Auth { $EncodeObject->EncodeOutput( \$Pw ); $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); + $Method = 'sha256'; $EncodeObject->EncodeInput( \$CryptedPw ); - $Method = 'sha256'; } # sha512 pw @@ -202,20 +201,20 @@ sub Auth { $EncodeObject->EncodeOutput( \$Pw ); $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); + $Method = 'sha512'; $EncodeObject->EncodeInput( \$CryptedPw ); - $Method = 'sha512'; } elsif ( $GetPw =~ m{^BCRYPT:} ) { # require module, log errors if module was not found - if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) - { + if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "CustomerUser: $User tried to authenticate with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", ); + return; } @@ -249,8 +248,8 @@ sub Auth { $SHAObject->add($Pw); $CryptedPw = $SHAObject->hexdigest(); + $Method = 'sha1'; $EncodeObject->EncodeInput( \$CryptedPw ); - $Method = 'sha1'; } # No-13-chars-long crypt pw (e.g. in Fedora28). @@ -269,18 +268,17 @@ sub Auth { # crypt pw else { - # strip salt only for (Extended) DES, not for any of modular crypt's + # strip salt only for (Extended) DES, not for any of modular crypts if ( $Salt !~ /^\$\d\$/ ) { $Salt =~ s/^(..).*/$1/; } + # encode output, needed by crypt() only non utf8 signs $EncodeObject->EncodeOutput( \$Pw ); $EncodeObject->EncodeOutput( \$Salt ); - - # encode output, needed by crypt() only non utf8 signs $CryptedPw = crypt( $Pw, $Salt ); + $Method = 'crypt'; $EncodeObject->EncodeInput( \$CryptedPw ); - $Method = 'crypt'; } # Debugging can only be activated in the source code, @@ -291,7 +289,7 @@ sub Auth { my $ExpectedPw = $GetPw; # Don't log plaintext passwords. - if ( $Self->{CryptType} eq 'plain' ) { + if ( $Method eq 'plain' ) { $EnteredPw = 'xxx'; $ExpectedPw = 'xxx'; } @@ -307,18 +305,19 @@ sub Auth { if ( !$Pw ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', - Message => - "CustomerUser: $User authentication without Pw!!! (REMOTE_ADDR: $RemoteAddr)", + Message => "CustomerUser: $User authentication without Pw!!! (REMOTE_ADDR: $RemoteAddr)", ); + return; } # login note - elsif ( ( $GetPw && $User && $UserID ) && $CryptedPw eq $GetPw ) { + elsif ( $GetPw && $User && $UserID && $CryptedPw eq $GetPw ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', Message => "CustomerUser: $User Authentication ok (REMOTE_ADDR: $RemoteAddr).", ); + return $User; } @@ -329,6 +328,7 @@ sub Auth { Message => "CustomerUser: $User Authentication with wrong Pw!!! (REMOTE_ADDR: $RemoteAddr)" ); + return; } @@ -336,9 +336,9 @@ sub Auth { else { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', - Message => - "CustomerUser: $User doesn't exist or is invalid!!! (REMOTE_ADDR: $RemoteAddr)" + Message => "CustomerUser: $User doesn't exist or is invalid!!! (REMOTE_ADDR: $RemoteAddr)" ); + return; } } From bdcc38f10a86c00d56a29c2a475fe506cfb15abe Mon Sep 17 00:00:00 2001 From: bernhard Date: Tue, 11 Feb 2025 10:05:45 +0100 Subject: [PATCH 4/4] Issue #4153: clarify code comments about the attribute NotParentDBObject --- Kernel/System/CustomerAuth/DB.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Kernel/System/CustomerAuth/DB.pm b/Kernel/System/CustomerAuth/DB.pm index eb985ec3f7..b16cfdc355 100644 --- a/Kernel/System/CustomerAuth/DB.pm +++ b/Kernel/System/CustomerAuth/DB.pm @@ -70,7 +70,8 @@ sub new { DisconnectOnDestruction => 1, ) || die "Can't connect to " . $ConfigObject->Get( 'Customer::AuthModule::DB::DSN' . $Param{Count} ); - # remember that we have the DBObject not from parent call + # Remember that the DBObject is not taken from object manager. + # The cleanup must be done seperately. $Self->{NotParentDBObject} = 1; } @@ -346,7 +347,7 @@ sub Auth { sub DESTROY { my $Self = shift; - # disconnect if it's not a parent DBObject + # disconnect if the DB object is not handled by the object manager if ( $Self->{NotParentDBObject} ) { if ( $Self->{DBObject} ) { $Self->{DBObject}->Disconnect();