Skip to content

Commit

Permalink
Item11605: Add email checks in registration
Browse files Browse the repository at this point in the history
 - Optional setting to block duplicate email registrations
 - Optional filter for email domains
 - Make TLD list configurable.
 - Log reasons for regsitration failures

git-svn-id: http://svn.foswiki.org/branches/Release01x01@14214 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
GeorgeClark authored and GeorgeClark committed Mar 5, 2012
1 parent e0f30ad commit 33f9be7
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 24 deletions.
251 changes: 244 additions & 7 deletions UnitTestContrib/test/unit/RegisterTests.pm
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ EOF
return;
}

sub loadExtraConfig {
my $this = shift;
$this->SUPER::loadExtraConfig(@_);

$Foswiki::cfg{Register}{UniqueEmail} = 0;
$Foswiki::cfg{Register}{EmailFilter} = '';
}

sub tear_down {
my $this = shift;

Expand Down Expand Up @@ -877,6 +885,237 @@ sub verify_rejectShortPassword {
return;
}

# Register a user with an email which is already in use.
sub verify_rejectDuplicateEmail {
my $this = shift;
$Foswiki::cfg{Register}{NeedVerification} = 0;
$Foswiki::cfg{Register}{UniqueEmail} = 1;
#$Foswiki::cfg{PasswordManager} = 'Foswiki::Users::HtPasswdUser';
$Foswiki::cfg{Register}{AllowLoginName} = 0;
my $query = Unit::Request->new(
{
'TopicName' => ['UserRegistration'],
'Twk1Email' => ['joe@gooddomain.net'],
'Twk1WikiName' => [ $this->{new_user_wikiname} ],
'Twk1Name' => [ $this->{new_user_fullname} ],
'Twk0Comment' => [''],
'Twk1FirstName' => [ $this->{new_user_fname} ],
'Twk1LastName' => [ $this->{new_user_sname} ],
'Twk1Password' => ['12345'],
'Twk1Confirm' => ['12345'],
'action' => ['register'],
}
);

$query->path_info("/$this->{users_web}/UserRegistration");
$this->createNewFoswikiSession( $Foswiki::cfg{DefaultUserLogin}, $query );
$this->{session}->net->setMailHandler( \&FoswikiFnTestCase::sentMail );

try {
$this->captureWithKey( register => $REG_UI_FN, $this->{session} );
}
catch Foswiki::OopsException with {
my $e = shift;
$this->assert_str_equals( "attention", $e->{template},
$e->stringify() );
$this->assert_str_equals( "thanks", $e->{def}, $e->stringify() );
$this->assert_equals( 2, scalar(@FoswikiFnTestCase::mails) );
my $done = '';
foreach my $mail (@FoswikiFnTestCase::mails) {
if ( $mail =~ /^Subject:.*Registration for/m ) {
if ( $mail =~ /^To: .*\bjoe\@gooddomain.net\b/m ) {
$this->assert( !$done, $done . "\n---------\n" . $mail );
$done = $mail;
}
else {
$this->assert_matches(
qr/To: $Foswiki::cfg{WebMasterName} <$Foswiki::cfg{WebMasterEmail}>/,
$mail
);
}
}
else {
$this->assert( 0, $mail );
}
}
$this->assert($done);
@FoswikiFnTestCase::mails = ();
}
catch Foswiki::AccessControlException with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
catch Error::Simple with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
otherwise {
$this->assert( 0, "expected an oops redirect" );
};

# Verify that The 2nd registration is stopped.
$query = Unit::Request->new(
{
'TopicName' => ['UserRegistration'],
'Twk1Email' => ['joe@gooddomain.net'],
'Twk1WikiName' => [ $this->{new_user_wikiname} . '2' ],
'Twk1Name' => [ $this->{new_user_fullname} . '2' ],
'Twk0Comment' => [''],
'Twk1FirstName' => [ $this->{new_user_fname} . '2' ],
'Twk1LastName' => [ $this->{new_user_sname} . '2' ],
'Twk1Password' => ['12345678'],
'Twk1Confirm' => ['12345678'],
'action' => ['register'],
}
);

$query->path_info("/$this->{users_web}/UserRegistration");
$this->createNewFoswikiSession( $Foswiki::cfg{DefaultUserLogin}, $query );
$this->{session}->net->setMailHandler( \&FoswikiFnTestCase::sentMail );

try {
$this->captureWithKey( register => $REG_UI_FN, $this->{session} );
}
catch Foswiki::OopsException with {
my $e = shift;
$this->assert_str_equals( "attention", $e->{template},
$e->stringify() );
$this->assert_str_equals( "dup_email", $e->{def}, $e->stringify() );
$this->assert_equals( 0, scalar(@FoswikiFnTestCase::mails) );
@FoswikiFnTestCase::mails = ();
}
catch Foswiki::AccessControlException with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
catch Error::Simple with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
otherwise {
$this->assert( 0, "expected an oops redirect" );
};

return;
}

# Register a user with an email which is filtered by EmailFilter
sub verify_rejectFilteredEmail {
my $this = shift;
$Foswiki::cfg{Register}{NeedVerification} = 0;
$Foswiki::cfg{Register}{UniqueEmail} = 0;
# Include a trailing and other whitespace - a common config error
$Foswiki::cfg{Register}{EmailFilter} =
'@(?!( gooddomain\.com | gooddomain\.net )$) ';
$Foswiki::cfg{PasswordManager} = 'Foswiki::Users::HtPasswdUser';
$Foswiki::cfg{Register}{AllowLoginName} = 0;
my $query = Unit::Request->new(
{
'TopicName' => ['UserRegistration'],
'Twk1Email' => [ $this->{new_user_email} ],
'Twk1WikiName' => [ $this->{new_user_wikiname} ],
'Twk1Name' => [ $this->{new_user_fullname} ],
'Twk0Comment' => [''],
'Twk1FirstName' => [ $this->{new_user_fname} ],
'Twk1LastName' => [ $this->{new_user_sname} ],
'Twk1Password' => ['12345'],
'Twk1Confirm' => ['12345'],
'action' => ['register'],
}
);

$query->path_info("/$this->{users_web}/UserRegistration");
$this->createNewFoswikiSession( $Foswiki::cfg{DefaultUserLogin}, $query );
$this->{session}->net->setMailHandler( \&FoswikiFnTestCase::sentMail );

try {
$this->captureWithKey( register => $REG_UI_FN, $this->{session} );
}
catch Foswiki::OopsException with {
my $e = shift;
$this->assert_str_equals( "attention", $e->{template},
$e->stringify() );
$this->assert_str_equals( "rej_email", $e->{def}, $e->stringify() );
$this->assert_equals( 0, scalar(@FoswikiFnTestCase::mails) );
@FoswikiFnTestCase::mails = ();
}
catch Foswiki::AccessControlException with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
catch Error::Simple with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
otherwise {
$this->assert( 0, "expected an oops redirect" );
};

# Also verify that a good domain makes it through
$query = Unit::Request->new(
{
'TopicName' => ['UserRegistration'],
'Twk1Email' => ['joe@gooddomain.net'],
'Twk1WikiName' => [ $this->{new_user_wikiname} ],
'Twk1Name' => [ $this->{new_user_fullname} ],
'Twk0Comment' => [''],
'Twk1FirstName' => [ $this->{new_user_fname} ],
'Twk1LastName' => [ $this->{new_user_sname} ],
'Twk1Password' => ['12345678'],
'Twk1Confirm' => ['12345678'],
'action' => ['register'],
}
);

$query->path_info("/$this->{users_web}/UserRegistration");
$this->createNewFoswikiSession( $Foswiki::cfg{DefaultUserLogin}, $query );
$this->{session}->net->setMailHandler( \&FoswikiFnTestCase::sentMail );

try {
$this->captureWithKey( register => $REG_UI_FN, $this->{session} );
}
catch Foswiki::OopsException with {
my $e = shift;
$this->assert_str_equals( "attention", $e->{template},
$e->stringify() );
$this->assert_str_equals( "thanks", $e->{def}, $e->stringify() );
$this->assert_equals( 2, scalar(@FoswikiFnTestCase::mails) );
my $done = '';
foreach my $mail (@FoswikiFnTestCase::mails) {
if ( $mail =~ /^Subject:.*Registration for/m ) {
if ( $mail =~ /^To: .*\bjoe\@gooddomain.net\b/m ) {
$this->assert( !$done, $done . "\n---------\n" . $mail );
$done = $mail;
}
else {
$this->assert_matches(
qr/To: $Foswiki::cfg{WebMasterName} <$Foswiki::cfg{WebMasterEmail}>/,
$mail
);
}
}
else {
$this->assert( 0, $mail );
}
}
$this->assert($done);
@FoswikiFnTestCase::mails = ();
}
catch Foswiki::AccessControlException with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
catch Error::Simple with {
my $e = shift;
$this->assert( 0, $e->stringify );
}
otherwise {
$this->assert( 0, "expected an oops redirect" );
};

return;
}

# Register a user with invalid characters in a field - like < html
sub verify_rejectEvilContent {
my $this = shift;
Expand All @@ -886,13 +1125,11 @@ sub verify_rejectEvilContent {
$Foswiki::cfg{Register}{AllowLoginName} = 0;
my $query = Unit::Request->new(
{
'TopicName' => ['UserRegistration'],
'Twk1Email' => [ $this->{new_user_email} ],
'Twk1WikiName' => [ $this->{new_user_wikiname} ],
'Twk1Name' => [ $this->{new_user_fullname} ],
'Twk0Comment' => ['<blah>'],

#'Twk1LoginName' => [ 'Bad@User' ],
'TopicName' => ['UserRegistration'],
'Twk1Email' => [ $this->{new_user_email} ],
'Twk1WikiName' => [ $this->{new_user_wikiname} ],
'Twk1Name' => [ $this->{new_user_fullname} ],
'Twk0Comment' => ['<blah>'],
'Twk1FirstName' => [ $this->{new_user_fname} ],
'Twk1LastName' => [ $this->{new_user_sname} ],
'Twk1Password' => ['123<><>aaa'],
Expand Down
4 changes: 2 additions & 2 deletions core/lib/Foswiki.pm
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,8 @@ BEGIN {
my $emailAtom = qr([A-Z0-9\Q!#\$%&'*+-/=?^_`{|}~\E])i; # Per RFC 5322

# Valid TLD's at http://data.iana.org/TLD/tlds-alpha-by-domain.txt
# Version 2011083000, Last Updated Tue Aug 30 14:07:02 2011 UTC
my $validTLD =
# Version 2012022300, Last Updated Thu Feb 23 15:07:02 2012 UTC
my $validTLD = $Foswiki::cfg{Email}{ValidTLD} ||
qr(AERO|ARPA|ASIA|BIZ|CAT|COM|COOP|EDU|GOV|INFO|INT|JOBS|MIL|MOBI|MUSEUM|NAME|NET|ORG|PRO|TEL|TRAVEL|XXX)i;

$regex{emailAddrRegex} = qr(
Expand Down
26 changes: 25 additions & 1 deletion core/lib/Foswiki.spec
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,20 @@ $Foswiki::cfg{Register}{HidePasswd} = $TRUE;
# You are recommended not to change this.
$Foswiki::cfg{Register}{RegistrationAgentWikiName} = 'RegistrationAgent';
# **BOOLEAN**
# Normally users can register multiple WikiNames using the same email address.
# Enable this parameter to prevent multiple registrations using the same email address.
$Foswiki::cfg{Register}{UniqueEmail} = $FALSE;
# **REGEX 80 EXPERT**
# This regular expression can be used to block certain email addresses from being used
# for registering users. It can be used to block some of the more common wikispam bots.
# If this regex matches the entered address, the registration is rejected. For example:<br/>
# <code>^.*@(lease-a-seo\.com|paydayloans).*$</code><br/>
# To block all domains and list only the permitted domains, use an expression of the format:<br/>
# <code>@(?!(example\.com|example\.net)$)</code>
$Foswiki::cfg{Register}{EmailFilter} = '';
# **STRING H**
# Configuration password (not prompted)
$Foswiki::cfg{Password} = '';
Expand Down Expand Up @@ -1272,7 +1286,7 @@ $Foswiki::cfg{Cache}{Servers} = '127.0.0.1:11211';
# to access external web pages.</p>
#---++ Email General
# <p>Settings controlling if and how Foswiki sends email including the identity of the sender
# <p>Settings controlling if and how Foswiki handles email including the identity of the sender
# and other expert settings controlling the email process.</p>
# **BOOLEAN**
# Enable email globally. Un-check this option to disable all outgoing
Expand Down Expand Up @@ -1304,6 +1318,16 @@ $Foswiki::cfg{NotifyTopicName} = 'WebNotify';
# Send email Date header using local "server time" instead of GMT
$Foswiki::cfg{Email}{Servertime} = $FALSE;
# **REGEX 80 EXPERT**
# This parameter is used to determine which Top Level domains are vaild
# when auto-linking email addresses. It is also used by UserRegistration to
# validate email addresses. Note, this parameter <em>only</em> controls
# matching of 3 character and longer TLDs. 2-character country codes and
# IP Address domains always permitted. See:<br/><code>
# Valid TLD's at http://data.iana.org/TLD/tlds-alpha-by-domain.txt<br/>
# Version 2012022300, Last Updated Thu Feb 23 15:07:02 2012 UTC</code>
$Foswiki::cfg{Email}{ValidTLD} = qr(AERO|ARPA|ASIA|BIZ|CAT|COM|COOP|EDU|GOV|INFO|INT|JOBS|MIL|MOBI|MUSEUM|NAME|NET|ORG|PRO|TEL|TRAVEL|XXX)i;
#---++ Email Server
# <p>Settings to select the destination mail server or local email agent used for forwarding email.</p>
Expand Down
Loading

0 comments on commit 33f9be7

Please sign in to comment.