diff -burN OpenTRS.prepatch/Kernel/Config/Defaults.pm OpenTRS/Kernel/Config/Defaults.pm --- OpenTRS.prepatch/Kernel/Config/Defaults.pm Tue Dec 10 11:52:58 2002 +++ OpenTRS/Kernel/Config/Defaults.pm Tue Dec 10 14:35:22 2002 @@ -1069,7 +1069,8 @@ # Customer::PrefernecesModule # (customer preferences module) - $Self->{'Customer::PrefernecesModule'} = 'Kernel::System::CustomerUser::Preferences::DB'; +# $Self->{'Customer::PrefernecesModule'} = 'Kernel::System::CustomerUser::Preferences::DB'; + $Self->{'Customer::PrefernecesModule'} = 'Kernel::System::CustomerUser::Preferences::LDAP'; # CustomerPreferencesTable* (needed for DB module) # (Stored CustomerPreferences table data.) @@ -1078,32 +1079,76 @@ $Self->{'Customer::PreferencesTableValue'} = 'preferences_value'; $Self->{'Customer::PreferencesTableUserID'} = 'user_id'; + # CustomerPreferencesTree (needed for LDAP module) + $Self->{'Customer::PreferencesLDAPHost'} = 'twix.net-m.de'; + $Self->{'Customer::PreferencesLDAPBaseDN'} = 'cn=netm,ou=resellers,ou=netmtest,o=netmldap'; + # what holdes the CID + $Self->{'Customer::PreferencesLDAPUserID'} = 'cn'; + # search scope + $Self->{'Customer::PreferencesLDAPSSCOPE'} = 'one'; + # comment field (company name?) + $Self->{'Customer::PreferencesLDAPcomment'} = 'netmFirmName1'; + # attribute mapping + # Title, FirstName, LastName, Email, CID, CompanyName(comment) + $Self->{'Customer::PreferencesLDAPATTR'} = 'netmContactCommTitle, netmContactCommFirstName, netmContactCommName, netmFirmEmail, cn, netmFirmName1'; + + # The following is valid but would only be necessary if the + # anonymous user does NOT have permission to read from the LDAP tree +# $Self->{'Customer::PreferencesLDAPUserDN'} = ''; +# $Self->{'Customer::PreferencesLDAPUserPw'} = ''; + + # CustomerUser # (customer user backend) - $Self->{CustomerUser} = { - Module => 'Kernel::System::CustomerUser::DB', - Params => { +# $Self->{CustomerUser} = { +# Module => 'Kernel::System::CustomerUser::DB', +# Params => { # Host => '', # User => '', # Password => '', # Database => '', - Table => 'customer_user', +# Table => 'customer_user', +# }, +# Map => [ +# # note: Login, Email and CustomerID needed! +# # var, frontend, storage, shown, required, storage-type +# [ 'UserSalutation', 'Salutation', 'salutation', 1, 0, 'var' ], +# [ 'UserFirstname', 'Firstname', 'first_name', 1, 1, 'var' ], +# [ 'UserLastname', 'Lastname', 'last_name', 1, 1, 'var' ], +# [ 'UserLogin', 'Login', 'login', 1, 1, 'var' ], +# [ 'UserPassword', 'Password', 'pw', 0, 1, 'var' ], +# [ 'UserEmail', 'Email', 'email', 1, 1, 'var' ], +# [ 'UserCustomerID', 'CustomerID', 'customer_id', 1, 1, 'var' ], +# [ 'UserComment', 'Comment', 'comment', 1, 0, 'var' ], +# [ 'ValidID', 'Valid', 'valid_id', 0, 1, 'int' ], +# ], +# Key => 'login', +# CustomerID => 'customer_id', +# ReadOnly => 1, +# }; + $Self->{CustomerUser} = { + Module => 'Kernel::System::CustomerUser::LDAP', + Params => { + Host => 'twix.net-m.de', + BaseDN => 'cn=netm,ou=resellers,ou=netmtest,o=netmldap', + SearchUserDN => '', + SearchUserPw => '', }, Map => [ # note: Login, Email and CustomerID needed! # var, frontend, storage, shown, required, storage-type - [ 'UserSalutation', 'Salutation', 'salutation', 1, 0, 'var' ], - [ 'UserFirstname', 'Firstname', 'first_name', 1, 1, 'var' ], - [ 'UserLastname', 'Lastname', 'last_name', 1, 1, 'var' ], - [ 'UserLogin', 'Login', 'login', 1, 1, 'var' ], + [ 'UserSalutation', 'Salutation', 'netmContactCommTitle', 1, 0, 'var' ], + [ 'UserFirstname', 'Firstname', 'netmContactCommFirstName', 1, 1, 'var' ], + [ 'UserLastname', 'Lastname', 'netmContactCommName', 1, 1, 'var' ], + [ 'UserLogin', 'Login', 'cn', 1, 1, 'var' ], [ 'UserPassword', 'Password', 'pw', 0, 1, 'var' ], - [ 'UserEmail', 'Email', 'email', 1, 1, 'var' ], - [ 'UserCustomerID', 'CustomerID', 'customer_id', 1, 1, 'var' ], - [ 'UserComment', 'Comment', 'comment', 1, 0, 'var' ], + [ 'UserEmail', 'Email', 'netmFirmEmail', 1, 1, 'var' ], + [ 'UserCustomerID', 'CustomerID', 'cn', 1, 1, 'var' ], + [ 'UserComment', 'Comment', 'netmFirmName1', 1, 0, 'var' ], [ 'ValidID', 'Valid', 'valid_id', 0, 1, 'int' ], ], Key => 'login', - CustomerID => 'customer_id', + CustomerID => 'cn', # ReadOnly => 1, }; diff -burN OpenTRS.prepatch/Kernel/Output/HTML/Standard/AgentPhoneNew.dtl OpenTRS/Kernel/Output/HTML/Standard/AgentPhoneNew.dtl --- OpenTRS.prepatch/Kernel/Output/HTML/Standard/AgentPhoneNew.dtl Fri Oct 25 15:30:22 2002 +++ OpenTRS/Kernel/Output/HTML/Standard/AgentPhoneNew.dtl Tue Dec 10 12:38:11 2002 @@ -78,7 +78,7 @@ $Text{"Next ticket state"}:$Data{"NextStatesStrg"} - $Text{"CustomerID"}: + $Text{"CustomerID"}:$Data{"CustomerStrg"} $Text{"Time units"}$Text{"$Config{"TimeUnits"}"}: diff -burN OpenTRS.prepatch/Kernel/System/CustomerUser/LDAP.pm OpenTRS/Kernel/System/CustomerUser/LDAP.pm --- OpenTRS.prepatch/Kernel/System/CustomerUser/LDAP.pm Thu Jan 1 01:00:00 1970 +++ OpenTRS/Kernel/System/CustomerUser/LDAP.pm Tue Dec 10 17:38:49 2002 @@ -0,0 +1,434 @@ +# -- +# Kernel/System/CustomerUser/DB.pm - some customer user functions in LDAP +# Copyright (C) 2002 Wiktor Wodecki +# -- +# This software comes with ABSOLUTELY NO WARRANTY. For details, see +# the enclosed file COPYING for license information (GPL). If you +# did not receive this file, see http://www.gnu.org/licenses/gpl.txt. +# -- + +package Kernel::System::CustomerUser::LDAP; + +use strict; +use Net::LDAP; + +use vars qw(@ISA $VERSION); +$VERSION = '$Revision: 1.0 $'; +$VERSION =~ s/^.*:\s(\d+\.\d+)\s.*$/$1/; + +# -- +sub new { + my $Type = shift; + my %Param = @_; + + # allocate new hash for object + my $Self = {}; + bless ($Self, $Type); + # -- + # check needed objects + # -- + foreach (qw(DBObject ConfigObject LogObject PreferencesObject)) { + $Self->{$_} = $Param{$_} || die "Got no $_!"; + } + # -- + # Debug 0=off 1=on + # -- + $Self->{Debug} = 0; + + # -- + # get ldap preferences + # -- + $Self->{Host} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPHost') + || die "Need Customer::PreferencesLDAPHost in Kernel/Config.pm"; + $Self->{BaseDN} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPBaseDN') + || die "Need Customer::PreferencesLDAPBaseDN in Kernel/Config.pm"; + $Self->{UserID} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPUserID') + || die "Need Customer::PreferencesLDAPCID in Kernel/Config.pm"; + $Self->{comment} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPcomment') + || die "Need Customer::PreferencesLDAPcomment in Kernel/Config.pm"; + $Self->{SScope} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPSSCOPE') + || die "Need Customer::PreferencesLDAPSSCOPE in Kernel/Config.pm"; + $Self->{SearchUserDN} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPUserDN') || ''; + $Self->{SearchUserPw} = $Self->{ConfigObject}->Get('Customer::PreferencesLDAPUserPw') || ''; + + return $Self; +} +# -- +sub CustomerList { + my $Self = shift; + my %Param = @_; + my $Valid = defined $Param{Valid} ? $Param{Valid} : 1; + # -- + # ldap connect and bind (maybe with SearchUserDN and SearchUserPw) + # -- + my $LDAP = Net::LDAP->new($Self->{Host}) or die "$@"; + if (!$LDAP->bind(dn => $Self->{SearchUserDN}, password => $Self->{SearchUserPw})) { + $Self->{LogObject}->Log( + Priority => 'error', + Message => "First bind failed!", + ); + return; + } + + # -- + # perform user search + # FIXME: check for valid customers + # -- + my $Users = $LDAP->search ( + base => $Self->{BaseDN}, + scope => $Self->{SScope}, + attrs => $Self->{UserID},$Self->{UserID},$Self->{comment}, + filter => '', + ); + # -- + # take down session + # -- + $LDAP->unbind; + + return %$Users; +} +# -- +sub CustomerUserList { + my $Self = shift; + my %Param = @_; + my $Valid = defined $Param{Valid} ? $Param{Valid} : 1; + $Self->{LogObject}->Log( + Priority => 'error', + Message => "d3", + ); + # -- + # ldap connect and bind (maybe with SearchUserDN and SearchUserPw) + # -- + my $LDAP = Net::LDAP->new($Self->{Host}) or die "$@"; + if (!$LDAP->bind(dn => $Self->{SearchUserDN}, password => $Self->{SearchUserPw})) { + $Self->{LogObject}->Log( + Priority => 'error', + Message => "First bind failed!", + ); + return; + } + + # -- + # perform user search + # FIXME: check for valid customers + # -- + my %Users = $LDAP->search ( + base => $Self->{BaseDN}, + scope => $Self->{SScope}, + attrs => $Self->{UserID},$Self->{UserID},$Self->{UserID}, + filter => '', + ); + # -- + # take down session + # -- + $LDAP->unbind; + + $Self->{LogObject}->Log( + Priority => 'error', + Message => "d4", + ); + return %Users; +} +# -- +sub CustomerUserDataGet { + my $Self = shift; + my %Param = @_; + my %Data; + # -- + # check needed stuff + # -- + if (!$Param{User} && !$Param{CustomerID}) { + $Self->{LogObject}->Log(Priority => 'error', Message => "Need User or CustomerID!"); + return; + } + # -- + # ldap connect and bind (maybe with SearchUserDN and SearchUserPw) + # -- + my $LDAP = Net::LDAP->new($Self->{Host}) or die "$@"; + if (!$LDAP->bind(dn => $Self->{SearchUserDN}, password => $Self->{SearchUserPw})) { + $Self->{LogObject}->Log( + Priority => 'error', + Message => "First bind failed!", + ); + return; + } + + # -- + # perform user search + # FIXME: check for valid customers + # -- + my $attrs = ''; + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + $attrs .= "\'$Entry->[2]\',"; + } + $attrs = substr $attrs,0,-1; + my $Result = $LDAP->search ( + base => $Self->{BaseDN}, + scope => $Self->{SScope}, + filter => '(cn='.$Param{CustomerID}.')', + attrs => $attrs, + ); + my $result2 = $Result->entry(0); + + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + $Data{$Entry->[0]} = $result2->get_value( $Entry->[2] ); + } + + # -- + # check data + # -- + if (! exists $Data{UserLogin} && $Param{User}) { + $Self->{LogObject}->Log( + Priority => 'notice', + Message => "Panic! No UserData for customer user: '$Param{User}'!!!", + ); + # -- + # take down session + # -- + $LDAP->unbind; + return; + } + if (! exists $Data{UserLogin} && $Param{CustomerID}) { + $Self->{LogObject}->Log( + Priority => 'notice', + Message => "Panic! No UserData for customer id: '$Param{CustomerID}'!!!", + ); + # -- + # take down session + # -- + $LDAP->unbind; + return; + } + # compat! + $Data{UserID} = $Data{UserLogin}; + # -- + # get preferences + # -- + my %Preferences = $Self->{PreferencesObject}->GetPreferences(UserID => $Data{UserID}); + # -- + # take down session + # -- + $LDAP->unbind; + + # return data + return (%Data, %Preferences); +} +# -- +sub CustomerUserAdd { + my $Self = shift; + my %Param = @_; + # -- + # check needed stuff + # -- + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + if (!$Param{$Entry->[0]} && $Entry->[4]) { + $Self->{LogObject}->Log(Priority => 'error', Message => "Need $Entry->[0]!"); + return; + } + } + if (!$Param{UserID}) { + $Self->{LogObject}->Log(Priority => 'error', Message => "Need UserID!"); + return; + } + # -- + # check email address + # -- + if (!Email::Valid->address( + -address => $Param{UserEmail}, + -mxcheck => $Self->{ConfigObject}->Get('CustomerPanelMXCheck') || 1, + )) { + $Self->{LogObject}->Log( + Priority => 'error', + Message => "Email address ($Param{Email}) not valid ($Email::Valid::Details)!", + ); + return; + } + # -- + # quote params + # -- + $Param{UserPassword} = crypt($Param{UserPassword}, $Param{UserLogin}); + foreach (keys %Param) { + $Param{$_} = $Self->{DBObject}->Quote($Param{$_}) || ''; + } + # -- + # build insert + # -- + my $SQL = "INSERT INTO $Self->{CustomerTable} ("; + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + $SQL .= " $Entry->[2], "; + } + $SQL .= "create_time, create_by, change_time, change_by)"; + $SQL .= " VALUES ("; + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + if ($Entry->[5] =~ /^int$/i) { + $SQL .= " $Param{$Entry->[0]}, "; + } + else { + $SQL .= " '$Param{$Entry->[0]}', "; + } + } + $SQL .= "current_timestamp, $Param{UserID}, current_timestamp, $Param{UserID})"; + if ($Self->{DBObject}->Do(SQL => $SQL)) { + # -- + # log notice + # -- + $Self->{LogObject}->Log( + Priority => 'notice', + Message => "CustomerUser: '$Param{UserLogin}' created successfully ($Param{UserID})!", + ); + return $Param{UserLogin}; + } + else { + return; + } +} +# -- +sub CustomerUserUpdate { + my $Self = shift; + my %Param = @_; + # -- + # check needed stuff + # -- + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + if (!$Param{$Entry->[0]} && $Entry->[4]) { + $Self->{LogObject}->Log(Priority => 'error', Message => "Need $Entry->[0]!"); + return; + } + } + # -- + # check email address + # -- + if (!Email::Valid->address( + -address => $Param{UserEmail}, + -mxcheck => $Self->{ConfigObject}->Get('CustomerPanelMXCheck') || 1, + )) { + $Self->{LogObject}->Log( + Priority => 'error', + Message => "Email address ($Param{Email}) not valid ($Email::Valid::Details)!", + ); + return; + } + # -- + # get old user data (pw) + # -- + my %UserData = $Self->CustomerUserDataGet(User => $Param{ID}); + # -- + # quote params + # -- + foreach (keys %Param) { + $Param{$_} = $Self->{DBObject}->Quote($Param{$_}) || ''; + } + # -- + # update db + # -- + my $SQL = "UPDATE $Self->{CustomerTable} SET "; + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + if ($Entry->[5] =~ /^int$/i) { + $SQL .= " $Entry->[2] = $Param{$Entry->[0]}, "; + } + elsif ($Entry->[0] !~ /^UserPassword$/i) { + $SQL .= " $Entry->[2] = '$Param{$Entry->[0]}', "; + } + } + $SQL .= " change_time = current_timestamp, "; + $SQL .= " change_by = $Param{UserID} "; + $SQL .= " WHERE ".$Self->{ConfigObject}->Get('CustomerUser')->{Key}." = '$Param{ID}'"; + + if ($Self->{DBObject}->Do(SQL => $SQL)) { + # -- + # log notice + # -- + $Self->{LogObject}->Log( + Priority => 'notice', + Message => "CustomerUser: '$Param{UserLogin}' updated successfully ($Param{UserID})!", + ); + # -- + # check pw + # -- + my $GetPw = $UserData{UserPassword} || ''; + if ($GetPw ne $Param{UserPassword}) { + $Self->SetPassword(UserLogin => $Param{UserLogin}, PW => $Param{UserPassword}); + } + return 1; + } + else { + return; + } +} +# -- +sub SetPassword { + my $Self = shift; + my %Param = @_; + my $Pw = $Param{PW} || ''; + # -- + # check needed stuff + # -- + if (!$Param{UserLogin}) { + $Self->{LogObject}->Log(Priority => 'error', Message => "Need UserLogin!"); + return; + } + # -- + # crypt pw + # -- + my $NewPw = $Self->{DBObject}->Quote(crypt($Pw, $Param{UserLogin})); + # -- + # update db + # -- + foreach my $Entry (@{$Self->{ConfigObject}->Get('CustomerUser')->{Map}}) { + if ($Entry->[0] =~ /^UserPassword$/i) { + $Param{PasswordCol} = $Entry->[2]; + } + if ($Entry->[0] =~ /^UserLogin$/i) { + $Param{LoginCol} = $Entry->[2]; + } + } + if ($Self->{DBObject}->Do( + SQL => "UPDATE $Self->{CustomerTable} ". + " SET ". + " $Param{PasswordCol} = '$NewPw' ". + " WHERE ". + " $Param{LoginCol} = '$Param{UserLogin}'", + )) { + # -- + # log notice + # -- + $Self->{LogObject}->Log( + Priority => 'notice', + Message => "CustomerUser: '$Param{UserLogin}' changed password successfully!", + ); + return 1; + } + else { + return; + } +} +# -- +sub GetGroups { + return; +} +# -- +sub GenerateRandomPassword { + my $Self = shift; + my %Param = @_; + # Generated passwords are eight characters long by default. + my $Size = $Param{Size} || 8; + + # The list of characters that can appear in a randomly generated password. + # Note that users can put any character into a password they choose themselves. + my @PwChars = (0..9, 'A'..'Z', 'a'..'z', '-', '_', '!', '@', '#', '$', '%', '^', '&', '*'); + + # The number of characters in the list. + my $PwCharsLen = scalar(@PwChars); + + # Generate the password. + my $Password = ''; + for ( my $i=0 ; $i<$Size ; $i++ ) { + $Password .= $PwChars[rand($PwCharsLen)]; + } + + # Return the password. + return $Password; +} +# -- + +1; diff -burN OpenTRS.prepatch/Kernel/System/CustomerUser.pm OpenTRS/Kernel/System/CustomerUser.pm --- OpenTRS.prepatch/Kernel/System/CustomerUser.pm Sat Dec 7 22:03:42 2002 +++ OpenTRS/Kernel/System/CustomerUser.pm Tue Dec 10 15:59:09 2002 @@ -34,10 +34,10 @@ # -- # load generator customer preferences module # -- - my $GeneratorModule = $Self->{ConfigObject}->Get('Customer::PrefernecesModule') + my $GeneratorModule = $Self->{ConfigObject}->Get('Customer::PreferencesModule') || 'Kernel::System::CustomerUser::Preferences::DB'; eval "require $GeneratorModule"; - $Self->{PrefernecesObject} = $GeneratorModule->new(%Param); + $Self->{PreferencesObject} = $GeneratorModule->new(%Param); # -- # load generator customer user module # -- @@ -46,7 +46,7 @@ eval "require $GeneratorModule"; $Self->{CustomerUserObject} = $GeneratorModule->new( %Param, - PreferencesObject => $Self->{PrefernecesObject}, + PreferencesObject => $Self->{PreferencesObject}, ); return $Self; @@ -94,12 +94,12 @@ # -- sub GetPreferences { my $Self = shift; - return $Self->{PrefernecesObject}->GetPreferences(@_); + return $Self->{PreferencesObject}->GetPreferences(@_); } # -- sub SetPreferences { my $Self = shift; - return $Self->{PrefernecesObject}->SetPreferences(@_); + return $Self->{PreferencesObject}->SetPreferences(@_); } # -- diff -burN OpenTRS.prepatch/Kernel/System/User.pm OpenTRS/Kernel/System/User.pm --- OpenTRS.prepatch/Kernel/System/User.pm Sat Dec 7 19:59:04 2002 +++ OpenTRS/Kernel/System/User.pm Tue Dec 10 15:59:42 2002 @@ -46,10 +46,10 @@ # -- # load generator customer preferences module # -- - my $GeneratorModule = $Self->{ConfigObject}->Get('User::PrefernecesModule') + my $GeneratorModule = $Self->{ConfigObject}->Get('User::PreferencesModule') || 'Kernel::System::User::Preferences::DB'; eval "require $GeneratorModule"; - $Self->{PrefernecesObject} = $GeneratorModule->new(%Param); + $Self->{PreferencesObject} = $GeneratorModule->new(%Param); return $Self; @@ -447,12 +447,12 @@ # -- sub SetPreferences { my $Self = shift; - return $Self->{PrefernecesObject}->SetPreferences(@_); + return $Self->{PreferencesObject}->SetPreferences(@_); } # -- sub GetPreferences { my $Self = shift; - return $Self->{PrefernecesObject}->GetPreferences(@_); + return $Self->{PreferencesObject}->GetPreferences(@_); } # -- diff -burN OpenTRS.prepatch/scripts/DBUpdate.postgresql.sql OpenTRS/scripts/DBUpdate.postgresql.sql --- OpenTRS.prepatch/scripts/DBUpdate.postgresql.sql Sat Dec 7 20:06:05 2002 +++ OpenTRS/scripts/DBUpdate.postgresql.sql Tue Dec 10 12:23:20 2002 @@ -1,18 +1,3 @@ --- -- --- Update an existing OpenTRS database to the current state. --- Copyright (C) 2001-2002 Martin Edenhofer --- -- --- $Id: DBUpdate.postgresql.sql,v 1.8 2002/12/07 19:06:05 martin Exp $ --- -- --- --- usage: cat DBUpdate.postgresql.sql | psql otrs --- --- -- - --- -- --- 0.5 BETA 9 upgrate --- -- --- table for db loop protection backend module CREATE TABLE ticket_loop_protection ( sent_to VARCHAR (250) NOT NULL,