App-CamelPKI
view release on metacpan or search on metacpan
t/lib/App/CamelPKI/Test.pm view on Meta::CPAN
B<App::CamelPKI::Test> - L<App::CamelPKI> Tests.
=head1 SYNOPSIS
=for My::Tests::Below "synopsis" begin
use App::CamelPKI::Test qw(:default %test_der_DNs);
use Test::Group;
my $utf8 = App::CamelPKI::Test->test_simple_utf8();
run_perl_ok(<<"SCRIPT");
use App::CamelPKI::Test;
warn "Hello world";
SCRIPT
=for My::Tests::Below "synopsis" end
=for My::Tests::Below "synopsis-asn1" begin
use App::CamelPKI::Test qw(x509_decoder);
my $dn_as_tree = x509_decoder('Name')->decode($dn_der);
=for My::Tests::Below "synopsis-asn1" end
server_start();
server_stop();
=head1 DESCRIPTION
This module is a library which aims at simplifying App-PKI test writing.
It started as a raw copy of I<Crypt::OpenSSL::CA:Test> you can find in
the C<t/lib> directory of the source L<Crypt::OpenSSL::CA> CPAN source
package.
=head1 EXPORTED FUNCTIONS
All functions described in this section factor some useful test
tactics and are exported by default. The L</SAMPLE INPUTS> may also
be exported upon request.
=over
=cut
use Test::Builder;
use Test::More;
use Test::Group;
use File::Find;
use File::Path ();
use File::Spec::Functions qw(catfile catdir);
use File::Slurp;
use File::Temp ();
use POSIX ":sys_wait_h";
use File::Which ();
use IO::Socket::SSL;
use LWP::UserAgent;
use HTTP::Request;
#pour formulaires
use URI::URL;
use HTTP::Request::Common;
use HTTP::Request::Form;
use HTML::TreeBuilder 3.0;
use base 'Exporter';
BEGIN {
our @EXPORT =
qw(openssl_path run_thru_openssl run_dumpasn1
run_perl run_perl_ok
certificate_looks_ok
certificate_chain_ok certificate_chain_invalid_ok
x509_schema x509_decoder
run_php run_php_script
http_request_prepare http_request_execute
plaintextcall_remote
call_remote formcall_remote formreq_remote
jsoncall_local jsonreq_remote jsoncall_remote
is_php_cli_present);
our @EXPORT_OK = (@EXPORT,
qw(test_simple_utf8 test_bmp_utf8
@test_DN_CAs
%test_der_DNs
%test_public_keys
%test_reqs_SPKAC %test_reqs_PKCS10
%test_keys_plaintext %test_keys_password
%test_self_signed_certs %test_rootca_certs
%test_entity_certs
test_CRL
server_start server_stop server_port
create_camel_pki_conf_php
camel_pki_chain
));
our %EXPORT_TAGS = ("default" => \@EXPORT);
}
=item I<plaintextcall_remote($url)>
Qureies a real Apache server at $url, which must be fully-qualified.
Throws an exception if the HTTP request isn't a success; otherwise,
Returns the C<text/plain> response as a string.
Available named options are:
=over
=item I<< -certificate => $certobj >>
=item I<< -certificate => $certpem >>
The certificate to identify oneself as, as an L<App::CamelPKI::Certificate>
instance or PEM string.
=item I<< -key => $keyobj >>
=item I<< -key => $keypem >>
The private key to use along with the certificate, as an
L<App::CamelPKI::PrivateKey> instance or PEM string.
=cut
sub plaintextcall_remote {
t/lib/App/CamelPKI/Test.pm view on Meta::CPAN
return http_request_execute($req, @args);
}
=item I<jsoncall_remote($url, $struct, %args)>
Like L</jsonreq_remote> but instead of returning an L<HTTP::Response>
object, returns the decoded JSON data structure by reference and
throws an exception if the HTTP request isn't a success or doesn't
decode properly.
=cut
sub jsoncall_remote {
my $response = jsonreq_remote(@_);
my $content = $response->content;
die sprintf("jsoncall_remote: failed with code %d\n%s\n",
$response->code, $content) if ! $response->is_success;
my $retval = eval { JSON::from_json($content) };
return $retval if defined $retval;
die $content;
}
=item I<call_remote($url)>
Gets $url and return the result.
=cut
sub call_remote {
my ($url, @args) = @_;
my $ua = LWP::UserAgent->new;
my $req = http_request_prepare($url, @args);
my $res = http_request_execute($req, @args);
my $content = $res->content;
die sprintf("call_remote: failed with code %d\n%s\n",
$res->code, $content) if ! $res->is_success;
return $content if defined $content;
die $content;
}
=item I<formreq_remote($url $struct, $button, @args)>
Call a form and fill it based on $struct, then push on $button
=cut
sub formreq_remote {
my ($url, $structure, $button, @args) = @_;
my $ua = LWP::UserAgent->new;
my $req = http_request_prepare($url, @args);
my $res = http_request_execute($req, @args);
my $tree = HTML::TreeBuilder->new;
$tree->parse($res->content);
$tree->eof();
my @Forms = $tree->find_by_tag_name('FORM');
die "No forms in page" unless @Forms;
my $f = HTTP::Request::Form->new($Forms[0], $url);
foreach my $part (keys(%$structure)){
$f->field($part, $structure->{$part});
}
my $response = http_request_execute($f->press($button), @args);
return $response;
}
=item I<formcall_remote($url, $struct, %args)>
Like L</jsonreq_remote> but instead of returning an L<HTTP::Response>
object, returns the page and
throws an exception if the HTTP request isn't a success .
=cut
sub formcall_remote {
my $response = formreq_remote(@_);
my $content = $response->content;
die sprintf("formcall_remote: failed with code %d\n%s\n",
$response->code, $content) if ! $response->is_success;
return $content if defined $content;
die $content;
}
=item I<http_request_prepare($url, %args)>
=item I<http_request_execute($request, %args)>
These functions factor code between L</jsonreq_remote>,
L</plaintextcall_remote> and such, although they may also be called
directly. I<http_request_prepare> creates and returns and returns a GET
L<HTTP::Request> object that the caller may further tweak, prior to
passing it along to I<http_request_execute>, which in turn does the HTTP/S
request and returns an L<HTTP::Response> object. Named arguments are
the same as in L</jsonreq_remote>, L</plaintextcall_remote> or
L</jsoncall_remote>.
=cut
sub http_request_prepare {
my ($url) = @_;
return HTTP::Request->new("GET", $url);
}
sub http_request_execute {
my ($req, %args) = @_;
die "Bad argument $req" unless eval { $req->isa("HTTP::Request") };
# Trust me, snarfing this undocumented variable really is the
# most elegant way of causing LWP to use a client certificate.
# I've gone through these hoops many, many times.
local @LWP::Protocol::http::EXTRA_SOCK_OPTS;
if ($args{-key} && $args{-certificate}) {
my $keysdir = catdir(tempdir(), "test_ssl_client_keys");
if (! -d $keysdir) {
mkdir($keysdir) or die "Cannot mkdir($keysdir): $!\n";
}
write_file(my $clientcertfile = catfile($keysdir, "cert.pem"),
(ref($args{-certificate}) ?
$args{-certificate}->serialize() :
$args{-certificate}));
write_file(my $clientkeyfile = catfile($keysdir, "key.pem"),
(ref($args{-key}) ? $args{-key}->serialize() :
$args{-key}));
@LWP::Protocol::http::EXTRA_SOCK_OPTS =
(SSL_use_cert => 1,
SSL_cert_file => $clientcertfile,
SSL_key_file => $clientkeyfile,
);
}
return LWP::UserAgent->new->request($req);
}
=item I<camel_pki_chain>
Returns the certification chain of the App-PKI application under test,
starting with the Operational CA certificate.
=cut
sub camel_pki_chain {
require Catalyst::Test;
Catalyst::Test->import("App::CamelPKI");
my $req = Catalyst::Utils::request("/ca/certificate_chain_pem");
my $resp = Catalyst::Test::local_request("App::CamelPKI", $req)
->content;
return map {$_->serialize} (App::CamelPKI::Certificate->parse_bundle($resp));
}
=item I<openssl_path>
Returns the path to the C<openssl> command-line tool, if it is known,
or undef. Useful for skipping tests that depend on
L</run_thru_openssl> being able to run.
=cut
sub openssl_path {
my ($openssl_bin) =
( `which openssl 2>/dev/null` =~ m/^(.*)/ ); # Chopped, untainted
return if ! ($openssl_bin && -x $openssl_bin);
return $openssl_bin;
}
=item I<run_thru_openssl($stdin_text, $arg1, $arg2, ...)>
( run in 0.796 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )