From: Thomas Berezansky Date: Fri, 9 Dec 2011 20:19:12 +0000 (-0500) Subject: OpenSRF Validator Service X-Git-Tag: osrf_rel_2_1_0-alpha1~21 X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=5e1fbcc1c8ae2f969dbeac93fe1da80c008ca42b;p=OpenSRF.git OpenSRF Validator Service Add a new Validator service, and EmailAddress validators. The service runs a chain of one or more validators, each one being fed the normalized output of the previous one. The return from each validator should be a hash of valid (0 or 1), the new normalized output (the untouched input if invalid or nothing needed to be changed), and if invalid an error string. Optionally, a validator can also include an "additionals" hash of extra information to be included in the final response. The complete list of validators included is: OpenSRF::Application::Validator::Base The base validator. Always returns valid. OpenSRF::Application::Validator::Invalid Always returns invalid for testing purposes. OpenSRF::Application::Validator::EmailAddress::Regex Does a very basic regular expression check on email addresses. OpenSRF::Application::Validator::EmailAddress::DNS Uses Net::DNS to look up the domain on an email address Signed-off-by: Thomas Berezansky Signed-off-by: Dan Scott --- diff --git a/examples/opensrf.xml.example b/examples/opensrf.xml.example index 0dc2704..9b0ed97 100644 --- a/examples/opensrf.xml.example +++ b/examples/opensrf.xml.example @@ -182,6 +182,45 @@ vim:et:ts=2:sw=2: 5 + + + 1 + 1 + perl + OpenSRF::Application::Validator + 17 + + opensrf.validator_unix.sock + opensrf.validator_unix.pid + 1000 + opensrf.validator_unix.log + 5 + 15 + 3 + 5 + + + + + + + OpenSRF::Application::Validator::EmailAddress::Regex + + + OpenSRF::Application::Validator::EmailAddress::DNS + 1 + + 0 + + + + 127.0.0.1,67.215.65.132 + + + + + + @@ -202,6 +241,7 @@ vim:et:ts=2:sw=2: opensrf.settings opensrf.math opensrf.dbmath + opensrf.validator diff --git a/src/extras/Makefile.install b/src/extras/Makefile.install index 56725c9..51d8890 100644 --- a/src/extras/Makefile.install +++ b/src/extras/Makefile.install @@ -101,6 +101,7 @@ DEBS = \ libgdbm-dev \ liblog-log4perl-perl\ libmodule-build-perl\ + libnet-dns-perl\ libnet-jabber-perl\ libperl-dev\ libreadline5-dev\ @@ -161,6 +162,7 @@ CENTOS = \ perl-Log-Log4perl \ perl-Memcached-libmemcached \ perl-Module-Build \ + perl-Net-DNS \ perl-Net-Server \ perl-Template-Toolkit \ perl-Test-Pod \ @@ -219,6 +221,7 @@ FEDORAS = \ perl-libwww-perl \ perl-Log-Log4perl \ perl-Module-Build \ + perl-Net-DNS \ perl-Net-Jabber \ perl-Net-Server \ perl-RPC-XML \ diff --git a/src/perl/lib/OpenSRF/Application/Validator.pm b/src/perl/lib/OpenSRF/Application/Validator.pm new file mode 100644 index 0000000..dc9b072 --- /dev/null +++ b/src/perl/lib/OpenSRF/Application/Validator.pm @@ -0,0 +1,50 @@ +package OpenSRF::Application::Validator; +use base qw/OpenSRF::Application/; +use OpenSRF::Application; +use OpenSRF::Utils::SettingsClient; +use OpenSRF::Utils::Logger; +use Module::Load; + +my $logger = OpenSRF::Utils::Logger; +my %modules; + +sub initialize { + my $sc = OpenSRF::Utils::SettingsClient->new; + my $validators = $sc->config_value( apps => 'opensrf.validator' => app_settings => 'validators' ); + while(my $module = each %$validators ) { + __PACKAGE__->register_method( + api_name => "opensrf.validator.$module.validate", + method => 'do_validate', + argc => 1, + validator_name => $module + ); + $modules{$module} = $validators->{$module}; + } +} + +sub do_validate { + my $self = shift; + my $client = shift; + my $input = shift; + my $return = { 'valid' => 1, 'normalized' => $input }; # Default return + my $validators = $modules{$self->{validator_name}}->{modules}; + my @validator_names = sort keys %$validators; + my $additionals = (); + + my $submodulename, $submodule; + while($return->{valid} && ($submodulename = shift @validator_names)) { + $submodule = $validators->{$submodulename}; + my $implementation = $submodule->{implementation}; + $logger->debug("Running request through $submodulename ($implementation)"); + load $implementation; + my $result = $implementation->validate($return->{normalized}, $submodule); + if($result) { + $return = $result; + $additionals = {%$additionals, %{$return->{additionals}}} if $return->{additionals}; + } + } + $return->{additionals} = $additionals; + return $return; +} + +1; diff --git a/src/perl/lib/OpenSRF/Application/Validator/Base.pm b/src/perl/lib/OpenSRF/Application/Validator/Base.pm new file mode 100644 index 0000000..bf7d34f --- /dev/null +++ b/src/perl/lib/OpenSRF/Application/Validator/Base.pm @@ -0,0 +1,12 @@ +package OpenSRF::Application::Validator::Base; +use strict; +use warnings; + +sub validate { + my $self = shift; + my $input = shift; + my $settings = shift; + return { 'valid' => 1, 'normalized' => $input }; +} + +1; diff --git a/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/DNS.pm b/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/DNS.pm new file mode 100644 index 0000000..8121ccd --- /dev/null +++ b/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/DNS.pm @@ -0,0 +1,96 @@ +package OpenSRF::Application::Validator::EmailAddress::DNS; +use base qw/OpenSRF::Application::Validator::Base/; + +use OpenSRF::Application::Validator::Base; +use Net::DNS; + +use strict; +use warnings; + +sub validate { + my $self = shift; + my $input = shift; + my $settings = shift; + + my $return = { 'valid' => 0, 'normalized' => $input }; + + if(!$input->{emailaddress}) { + return { 'valid' => 0, 'normalized' => $input, 'error' => 'No Address' }; + } elsif ($input->{emailaddress} !~ /@([^@]+)$/) { + return { 'valid' => 0, 'normalized' => $input, 'error' => 'Bad Address - Regex Check Failed' }; + } + my $domain = $1; + my $checkMXA = $settings->{check_mx_a}; + my $checkAAAA = $settings->{check_aaaa}; + my $config_file = $settings->{config_file}; + my @badAddrs; + if($settings->{ignore_ips}) { + @badAddrs = split(',', $settings->{ignore_ips}); + } + my $res; + $res = Net::DNS::Resolver->new(config_file => $config_file, defnames => 0) if $config_file; + $res = Net::DNS::Resolver->new(defnames => 0) if !$config_file; + my @arecords; + # Look for MX records first + my $answer = $res->send($domain, 'MX'); + foreach($answer->answer) { + if($_->type eq 'MX') { + push(@arecords, $_->exchange); + } + } + if(@arecords) { + if($checkMXA) { + OUTER: foreach my $checkdomain (@arecords) { + $answer = $res->send($checkdomain, 'A'); + foreach my $record ($answer->answer) { + last if $record->type eq 'CNAME' || $record->type eq 'DNAME'; + if($record->type eq 'A') { + next if grep { $_ eq $record->address } @badAddrs; + $return->{valid} = 1; + last OUTER; + } + } + if($checkAAAA) { + $answer = $res->send($checkdomain, 'AAAA'); + foreach my $record ($answer->answer) { + last if $record->type eq 'CNAME' || $record->type eq 'DNAME'; + if($record->type eq 'AAAA') { + next if grep { $_ eq $record->address } @badAddrs; + $return->{valid} = 1; + last OUTER; + } + } + } + } + $return->{error} = "MX Records Invalid" if(!$return->{valid}); + } else { + $return->{valid} = 1; + } + } else { + $answer = $res->send($domain,'A'); + foreach my $record ($answer->answer) { + last if $record->type eq 'CNAME' || $record->type eq 'DNAME'; + if($record->type eq 'A') { + next if grep { $_ eq $record->address } @badAddrs; + $return->{valid} = 1; + last; + } + } + if(!$return->{valid} && $checkAAAA) { + $answer = $res->send($domain, 'AAAA'); + foreach my $record ($answer->answer) { + last if $record->type eq 'CNAME' || $record->type eq 'DNAME'; + if($record->type eq 'AAAA') { + next if grep { $_ eq $record->address } @badAddrs; + $return->{valid} = 1; + last; + } + } + } + $return->{error} = "No A Records Found" if(!$return->{valid}); + } + $return->{normalized}->{emailaddress} = lc($return->{normalized}->{emailaddress}) if($return->{valid}); + return $return; +} + +1; diff --git a/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/Regex.pm b/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/Regex.pm new file mode 100644 index 0000000..25036fc --- /dev/null +++ b/src/perl/lib/OpenSRF/Application/Validator/EmailAddress/Regex.pm @@ -0,0 +1,23 @@ +package OpenSRF::Application::Validator::EmailAddress::Regex; +use base qw/OpenSRF::Application::Validator::Base/; + +use OpenSRF::Application::Validator::Base; + +use strict; +use warnings; + +sub validate { + my $self = shift; + my $input = shift; + my $settings = shift; + + if(!$input->{emailaddress}) { + return { 'valid' => 0, 'normalized' => $input, 'error' => 'No Address' }; + } elsif ($input->{emailaddress} !~ /^.+@[^@]+\.[^@]{2,}$/) { + return { 'valid' => 0, 'normalized' => $input, 'error' => 'Bad Address - Regex Check Failed' }; + } + $input->{emailaddress} = lc($input->{emailaddress}); + return { 'valid' => 1, 'normalized' => $input }; +} + +1; diff --git a/src/perl/lib/OpenSRF/Application/Validator/Invalid.pm b/src/perl/lib/OpenSRF/Application/Validator/Invalid.pm new file mode 100644 index 0000000..76f9676 --- /dev/null +++ b/src/perl/lib/OpenSRF/Application/Validator/Invalid.pm @@ -0,0 +1,16 @@ +package OpenSRF::Application::Validator::Invalid; +use base qw/OpenSRF::Application::Validator::Base/; + +use OpenSRF::Application::Validator::Base; + +use strict; +use warnings; + +sub validate { + my $self = shift; + my $input = shift; + my $settings = shift; + return { 'valid' => 0, 'normalized' => $input, 'error' => 'Forced Invalid' }; +} + +1;