Experian-IDAuth
view release on metacpan or search on metacpan
lib/Experian/IDAuth.pm view on Meta::CPAN
package Experian::IDAuth;
use 5.010;
use strict;
use warnings;
our $VERSION = '2.53';
use Locale::Country;
use Path::Tiny;
use Syntax::Keyword::Try;
use WWW::Mechanize;
## no critic (DiscouragedModules)
use XML::Simple;
use XML::Twig;
use SOAP::Lite;
use File::MimeInfo::Magic;
use IO::Socket::SSL 'SSL_VERIFY_NONE';
use Carp;
use Digest::SHA qw(hmac_sha256_base64);
sub new {
my ($class, %args) = @_;
my $obj = bless {}, $class;
$obj->set($obj->defaults, %args);
return $obj;
}
sub defaults {
my $self = shift;
return (
username => 'experian_user',
password => '?',
private_key => 'private_key',
public_key => 'public_key',
members_url => 'https://proveid.experian.com',
api_uri => 'http://corpwsdl.oneninetwo',
api_proxy => 'https://xml.proveid.experian.com/IDSearch.cfc',
header_ns_url => 'http://xml.proveid.experian.com/xsd/Headers',
folder => '/tmp/proveid',
# if you're using a logger,
#logger => Log::Log4per::get_logger,
);
}
sub set {
my ($self, %args) = @_;
$self->{$_} = $args{$_} for keys %args;
return $self;
}
sub get_result {
my $self = shift;
my $search_option = $self->{search_option};
croak "invalid search_option $search_option" if $search_option !~ /(?:ProveID_KYC|CheckID)/;
$self->_do_192_authentication;
return $self->_get_result_proveid if $search_option eq 'ProveID_KYC';
return $self->_get_result_checkid;
}
sub save_pdf_result {
my $self = shift;
# Parse and convert the result to hash
my $result = $self->_xml_as_hash or croak 'no xml result in place';
# 192 reference which we should pass to 192 to download the result
my $our_ref = $result->{OurReference} or croak "No 'OurReference'; invalid save-pdf request";
my $url = $self->{members_url};
my $mech = WWW::Mechanize->new();
$mech->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => SSL_VERIFY_NONE,
SSL_key_file => "/etc/rmg/ssl/key/experian.key",
SSL_cert_file => "/etc/rmg/ssl/crt/experian.crt"
);
try {
# Get the login page
$mech->get("$url/signin/");
# Login to the members environments
$mech->submit_form(
with_fields => {
login => $self->{username},
password => $self->{password},
lib/Experian/IDAuth.pm view on Meta::CPAN
sub has_downloaded_pdf {
my $self = shift;
my $file_pdf = $self->_pdf_report_filename;
return 0 unless -e $file_pdf;
open my $fh, '<', $file_pdf or croak "Could not open $file_pdf: $!";
my $mime_type = mimetype($fh);
close $fh;
return $mime_type =~ /PDF/i;
}
sub has_done_request {
my $self = shift;
return -f $self->_xml_report_filename;
}
sub get_192_xml_report {
my $self = shift;
return Path::Tiny::path($self->_xml_report_filename)->slurp;
}
sub valid_country {
my $self = shift;
my $country = shift;
for (
# To make CheckID work well for non-UK countries we need to pass
# in drivers license, Passport MRZ, national ID number
#qw( ad at au be ca ch cz dk es fi fr gb gg hu ie im it je lu nl no pt se sk us )
qw ( gb im )
)
{
return 1 if $country eq $_;
}
return 0;
}
sub _build_request {
my $self = shift;
$self->{request_as_xml} =
'<xml><![CDATA[<Search>'
. $self->_build_authentication_tag
. $self->_build_country_code_tag
. $self->_build_person_tag
. $self->_build_addresses_tag
. $self->_build_telephones_tag
. $self->_build_search_reference_tag
. $self->_build_search_option_tag
. '</Search>]]></xml>';
return 1;
}
# This is built based Section 3b on the Experian User Guide
sub _2fa_header {
my $self = shift;
my $loginid = $self->{username};
my $password = $self->{password};
my $private_key = $self->{private_key};
my $public_key = $self->{public_key};
my $timestamp = time();
my $hash = hmac_sha256_base64($loginid, $password, $timestamp, $private_key);
# Digest::SHA doesn't pad it's outputs so we have to do it manually.
while (length($hash) % 4) {
$hash .= '=';
}
my $hmac_sig = $hash . '_' . $timestamp . '_' . $public_key;
return SOAP::Header->name('head:Signature')->value($hmac_sig);
}
# Send the given SOAP request to 192.com
sub _send_request {
my $self = shift;
my $request = $self->{request_as_xml} // croak 'needs request';
# Hide password
(my $request1 = $request) =~ s/\<Password\>.+\<\/Password\>/\<Password\>XXXXXXX<\/Password\>/;
# Create soap object
my $soap = SOAP::Lite->readable(1)->uri($self->{api_uri})->proxy($self->{api_proxy})->ns($self->{header_ns_url}, 'head');
$soap->transport->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => SSL_VERIFY_NONE
);
$soap->transport->timeout(60);
# Do it
my $som = $soap->search(SOAP::Data->type('xml' => $request), $self->_2fa_header());
croak "ERRTEXT: " . $som->fault->faultstring if $som->fault;
my $result = $som->result;
$self->{result_as_xml} = $result;
return 1;
}
sub _build_authentication_tag {
my $self = shift;
return "<Authentication><Username>$self->{username}</Username><Password>$self->{password}</Password></Authentication>";
}
sub _build_country_code_tag {
my $self = shift;
my $two_digit_country = $self->{residence};
my $three_digit_country = uc Locale::Country::country_code2code($two_digit_country, LOCALE_CODE_ALPHA_2, LOCALE_CODE_ALPHA_3);
croak "Client " . $self->{client_id} . " could not get country from residence [$two_digit_country]" unless $three_digit_country;
return "<CountryCode>$three_digit_country</CountryCode>";
}
sub _build_person_tag {
my $self = shift;
my $dob = $self->{date_of_birth} or croak "No date of birth for " . $self->{client_id};
if ($dob =~ /^(\d\d\d\d)/) {
( run in 2.143 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )