Patches for canonicalizing Emailadresses in all contexts (was Re: [rt-users] Problems with CanonicalizeEmailAddress in RT3)

Dirk Pape pape-rt at inf.fu-berlin.de
Thu Apr 24 03:33:49 EDT 2003


The problem (as describes from me in the thread):

if you used the feature to canonicalize Email-Adresses (merging Email 
adresses to one user), this canonicalization does not happen in all 
contexts where it was nessecary:

it did only take place, when loading a user by Email address into the 
system (User->LoadFromEmail)

it did not take place in the following contexts:

1. loading a CurrentUser from Email (CurrentUser->LoadFromEmail)
2. creating a new User (User->Create), e.g. when receiving a request from a 
new Email

esp. the latter is definitely a bug since it makes mailgate to throw an 
exception and not to handle the new mail, because the User is created with 
the old email address but the system later tries to load it with the 
canonicalized email address (user does not exist!!).

I also patched another bug (wrong backslash before 
$RT::CanonicalizeEmailAddressMatch in CanonicalizeEmailAddress)

I attach two files (CurrentUser_Local.pm an User_Local.pm), which I used to 
overload the necessary functions in Current_User.pm and User_Overlay.pm.

If someone would merge this with the current code, I would be happy.

Regards,
Dirk.

--Am Samstag, 12. April 2003 22:24 Uhr +0200 schrieb Dirk Pape 
<pape-rt at inf.fu-berlin.de>:

> Indeed I found that canonicalizeEmailAdress is *not* called on the
> from-adress when new email is received.
>
> The problem is that lib/RT/Interfaces/Email/Auth/MailFrom.pm calls
> CurrentUser->LoadFromEmail which is not "overlayed" in the same way as
> User->LoadFromEmail is in lib/RT/User_Overlay.pm
>
> I could change the behaviour to the (by me) intended one by patching
> lib/RT/Interfaces/Email/Auth/MailFrom.pm to use User->LoadFromEmail
> instead of CurrentUser->LoadFromEmail
>
> But then I ran into another error, which is suspect:
>
> RT3 accepts the email as a ticket but also bounces me an error message.
>
> before I write a CurrentUser_Overlay.pm in calling
> CanoicalizeEmailAddress in the same way as User::LoadFromEmail I wonder
>
> A) is it an intended change from RT2 to RT3 to *not* canonicalize
> Email-Adresses on receives? B) if yes, why is it so
> C) if no, what is the correct way to eliminate the bug?
>
> Thanks,
> Dirk.
>
> --On Donnerstag, 10. April 2003 11:14 Uhr +0200 Dirk Pape
> <pape-rt at inf.fu-berlin.de> wrote:
>
>> I am on the way to configure RT3 to behave like our "old" RT2 system.
>>
>> In RT2 we had changed the CanonicalizeEmailAddress subroutine in
>> config.pm to change email-adresses from domain "inf.fu-berlin.de" to
>> "mi.fu-berlin.de".
>>
>> In RT3 - to acchieve the same result - I defined in RT_Siteconfig.pm:
>>
>> Set($CanonicalizeEmailAddressMatch   , 'inf.fu-berlin.de$');
>> Set($CanonicalizeEmailAddressReplace , 'mi.fu-berlin.de');
>>
>> with the effect that pape at inf.fu-berlin.de cannot create tickets in a
>> queue where pape at mi.fu-berlin.de has rights to create. (I get the "Ticket
>> creation failed" mail)
>>
>> I verified that pape at mi.fu-berlin.de *can* create and
>> pape at inf.fu-berlin.de cannot create, so I think address canonicalization
>> does not take place.
>>
>> In a second step I patched lib/RT/User_Overlay.pm directly by copying the
>> subroutine CanonicalizeEmailAddress from our RT2-configuration into that
>> file.
>>
>> I restarted apache afterwards.
>>
>> But the behavior did not change: pape at mi.fu-berlin.de *can* create and
>> pape at inf.fu-berlin.de cannot create.
>>
>> Did anything change from RT2 to RT3 in the context where
>> CanonicalizeEmailAddress is called?
>>
>> Thanks,
>> Dirk.
>> _______________________________________________
>> rt-users mailing list
>> rt-users at lists.fsck.com
>> http://lists.fsck.com/mailman/listinfo/rt-users
>>
>> Have you read the FAQ? The RT FAQ Manager lives at http://fsck.com/rtfm
>
>
>
>
> _______________________________________________
> rt-users mailing list
> rt-users at lists.fsck.com
> http://lists.fsck.com/mailman/listinfo/rt-users
>
> Have you read the FAQ? The RT FAQ Manager lives at http://fsck.com/rtfm



-------------- next part --------------
use strict;
no warnings qw(redefine);

sub CanonicalizeEmailAddress {
    my $self = shift;
    my $email = shift;
    # Example: the following rule would treat all email
    # coming from a subdomain as coming from second level domain
    # foo.com
    if ($RT::CanonicalizeEmailAddressMatch && $RT::CanonicalizeEmailAddressReplace ) {
        $email =~ s/$RT::CanonicalizeEmailAddressMatch/$RT::CanonicalizeEmailAddressReplace/gi;
    }
    return ($email);
}

sub Create {
    my $self = shift;
    my %args = (
        Privileged => 0,
        Disabled => 0,
        EmailAddress => '',
        @_    # get the real argumentlist
    );

# the next two lines to cope with caonicalizing email addresses
# when creating users. Remember that for new users (autocreated on ticket
# submission) Name=EmailAddress, Hence Name has to be corrected as well.

    $args{'EmailAddress'} = $self->CanonicalizeEmailAddress($args{'EmailAddress'}); #!!pape
    $args{'Name'} = $self->CanonicalizeEmailAddress($args{'Name'}); #!!pape

    #Check the ACL
    unless ( $self->CurrentUser->HasRight(Right => 'AdminUsers', Object => $RT::System) ) {
        return ( 0, $self->loc('No permission to create users') );
    }


    # Privileged is no longer a column in users
    my $privileged = $args{'Privileged'};
    delete $args{'Privileged'};


    if ($args{'CryptedPassword'} ) {
        $args{'Password'} = $args{'CryptedPassword'};
        delete $args{'CryptedPassword'};
    }
    elsif ( !$args{'Password'} ) {
        $args{'Password'} = '*NO-PASSWORD*';
    }
    elsif ( length( $args{'Password'} ) < $RT::MinimumPasswordLength ) {
        return ( 0, $self->loc("Password too short") );
    }

    else {
        $args{'Password'} = $self->_GeneratePassword($args{'Password'});
    }

    #TODO Specify some sensible defaults.

    unless ( defined( $args{'Name'} ) ) {
        return ( 0, $self->loc("Must specify 'Name' attribute") );
    }

    #SANITY CHECK THE NAME AND ABORT IF IT'S TAKEN
    if ($RT::SystemUser) {   #This only works if RT::SystemUser has been defined
        my $TempUser = RT::User->new($RT::SystemUser);
        $TempUser->Load( $args{'Name'} );
        return ( 0, $self->loc('Name in use') ) if ( $TempUser->Id );

        return ( 0, $self->loc('Email address in use') )
          unless ( $self->ValidateEmailAddress( $args{'EmailAddress'} ) );
    }
    else {
        $RT::Logger->warning( "$self couldn't check for pre-existing users");
    }


    $RT::Handle->BeginTransaction();
    # Groups deal with principal ids, rather than user ids.
    # When creating this user, set up a principal Id for it.
    my $principal = RT::Principal->new($self->CurrentUser);
    my $principal_id = $principal->Create(PrincipalType => 'User',
                                Disabled => $args{'Disabled'},
                                ObjectId => '0');
    $principal->__Set(Field => 'ObjectId', Value => $principal_id);
    # If we couldn't create a principal Id, get the fuck out.
    unless ($principal_id) {
        $RT::Handle->Rollback();
        $self->crit("Couldn't create a Principal on new user create. Strange things are afoot at the circle K");
        return ( 0, $self->loc('Could not create user') );
    }

    delete $args{'Disabled'};

    $self->SUPER::Create(id => $principal_id , %args);
    my $id = $self->Id;

    #If the create failed.
    unless ($id) {
        $RT::Logger->error("Could not create a new user - " .join('-'. %args));

        return ( 0, $self->loc('Could not create user') );
    }


    #TODO post 2.0
    #if ($args{'SendWelcomeMessage'}) {
    #	#TODO: Check if the email exists and looks valid
    #	#TODO: Send the user a "welcome message" 
    #}



    my $aclstash = RT::Group->new($self->CurrentUser);
    my $stash_id = $aclstash->_CreateACLEquivalenceGroup($principal);

    unless ($stash_id) {
        $RT::Handle->Rollback();
        $self->crit("Couldn't stash the user in groumembers");
        return ( 0, $self->loc('Could not create user') );
    }

    $RT::Handle->Commit;

    #$RT::Logger->debug("Adding the user as a member of everyone"); 
    my $everyone = RT::Group->new($self->CurrentUser);
    $everyone->LoadSystemInternalGroup('Everyone');
    $everyone->AddMember($self->PrincipalId);

    if ($privileged)  {
        my $priv = RT::Group->new($self->CurrentUser);
        #$RT::Logger->debug("Making ".$self->Id." a privileged user");
        $priv->LoadSystemInternalGroup('Privileged');
        $priv->AddMember($self->PrincipalId);  
    } else {
        my $unpriv = RT::Group->new($self->CurrentUser);
        #$RT::Logger->debug("Making ".$self->Id." an unprivileged user");
        $unpriv->LoadSystemInternalGroup('Unprivileged');
        $unpriv->AddMember($self->PrincipalId);  
    }


   #  $RT::Logger->debug("Finished creating the user");
    return ( $id, $self->loc('User created') );
}

1;
-------------- next part --------------
use strict;
no warnings qw(redefine);

sub LoadByEmail {
    my $self    = shift;
    my $address = shift;

    # Never load an empty address as an email address.
    unless ($address) {
        return (undef);
    }

    $address = $self->CanonicalizeEmailAddress($address);

    #$RT::Logger->debug("Trying to load an email address: $address\n");
    return $self->LoadByCol( "EmailAddress", $address );
}

# copied from User_Overlay.pm
# we need canonicalizing also in CurrentUser->LoadByEmail

sub CanonicalizeEmailAddress {
    my $self = shift;
    my $email = shift;
    # Example: the following rule would treat all email
    # coming from a subdomain as coming from second level domain
    # foo.com

#    $RT::Logger->log(level => 'debug',
#                     message => "!!pape-vorher: $email"
#                    );

    if ($RT::CanonicalizeEmailAddressMatch && $RT::CanonicalizeEmailAddressReplace ) {
        $email =~ s/$RT::CanonicalizeEmailAddressMatch/$RT::CanonicalizeEmailAddressReplace/gi;
    }

#    $RT::Logger->log(level => 'debug',
#                     message => "!!pape-nachher: $email"
#                    );

    return ($email);
}

1;


More information about the rt-users mailing list