Apache2-API
view release on metacpan or search on metacpan
This file contains message digests of all files listed in MANIFEST,
signed via the Module::Signature module, version 0.88.
To verify the content in this distribution, first make sure you have
Module::Signature installed, then type:
% cpansign -v
It will check each file's integrity, as well as the signature's
validity. If "==> Signature verified OK! <==" is not displayed,
the distribution may already have been compromised, and you should
not run its Makefile.PL or Build.PL.
-----BEGIN PGP SIGNED MESSAGE-----
lib/Apache2/API/Password.pod view on Meta::CPAN
=encoding utf8
=head1 NAME
Apache2::API::Password - Create and verify HTTP Basic Auth password hashes (APR1/bcrypt/SHA-crypt)
=head1 SYNOPSIS
use Apache2::API::Password;
# Create a new hash from a cleartext password (random salt)
# MD5-crypt (APR1, "$apr1$") - default
my $ht = Apache2::API::Password->new( 'secret', create => 1 );
my $hash = $ht->hash; # "$apr1$abcd1234$...."
# Create APR1 with a provided salt (max 8 chars; [./0-9A-Za-z])
my $ht2 = Apache2::API::Password->new( 'secret', create => 1, salt => 'hfT7jp2q' );
say $ht2->hash;
# Wrap an existing APR1 ($apr1$) hash and verify user input
my $ht3 = Apache2::API::Password->new( '$apr1$hfT7jp2q$DcU1Hf5w2Q/9G8yqv1hbl.' );
my $ok = $ht3->matches( 'secret' );
# Bcrypt ($2y$), choose a cost (04..31); defaults to 12
my $b = Apache2::API::Password->new('s3cret', create => 1, algo => 'bcrypt', bcrypt_cost => 12);
say $b->hash; # "$2y$12$..."
# SHA-crypt ($5$ = SHA-256, $6$ = SHA-512), optionally set rounds
my $s6 = Apache2::API::Password->new('s3cret', create => 1, algo => 'sha512', sha_rounds => 150000);
say $s6->hash; # "$6$rounds=150000$..."
lib/Apache2/API/Password.pod view on Meta::CPAN
=back
All 64 encoding symbols (including trailing C<.> or C</>) are valid.
=head1 SECURITY NOTES
=over 4
=item * Empty passwords
All algorithms accept empty strings. An empty password will verify successfully if you store its hash. Avoid this in production.
=item * Legacy algorithm
APR1/MD5-crypt is legacy and weak by modern standards. Prefer C<bcrypt> (with a cost appropriate to your CPU budget) or C<sha512> (SHA-crypt) where bcrypt is not available; retain C<APR1> only for Apache compatibility. For bcrypt, remember the 72-byt...
=item * Salt generation
Salt generation requires either L<Crypt::URandom> or L<Bytes::Random::Secure> to be installed. If neither is available, C<make>, C<make_md5>, C<make_bcrypt>, C<make_sha256>, and C<make_sha512> will return an error. The use of the non-cryptographic C<...
=back
Accept_Encoding => 'gzip, deflate, br',
Accept_Language => 'en-GB,fr-FR;q=0.8,fr;q=0.6,ja;q=0.4,en;q=0.2',
),
keep_alive => 1,
);
Apache::TestRequest::user_agent( @ua_args, reset => 1 );
$ua = Apache::TestRequest->new( @ua_args );
# To get the fingerprint for the certificate in ./t/server.crt, do:
# echo "sha1\$$(openssl x509 -noout -in ./t/server.crt -fingerprint -sha1|perl -pE 's/^.*Fingerprint=|(\w{2})(?:\:?|$)/$1/g')"
$ua->ssl_opts(
# SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
# SSL_verify_mode => 0x00
# verify_hostname => 0,
SSL_fingerprint => 'sha1$DEE8650E44870896E821AAE4A5A24382174D100E',
# SSL_version => 'SSLv3',
# SSL_verfifycn_name => 'localhost',
);
}
$proto = HAS_SSL ? 'https' : 'http';
diag( "Host: '$host', port '$port'" ) if( $DEBUG );
};
use strict;
t/06.apr1.t view on Meta::CPAN
# use_ok( 'Apache2::API' ) || BAIL_OUT( 'Unable to load Apache2::API' );
use ok( 'Apache2::API' ) || BAIL_OUT( 'Unable to load Apache2::API' );
};
use strict;
use warnings;
# my $api = Apache2::API->new( debug => $DEBUG );
my $api = Apache2::API->new;
sub verify_apr1
{
my( $passwd, $hash ) = @_;
return(0) unless( defined( $passwd ) && defined( $hash ) );
return(0) unless( $hash =~ m!\A\$apr1\$([./0-9A-Za-z]{1,8})\$([./0-9A-Za-z]{22})\z! );
my( $salt, $body ) = ( $1, $2 );
my $calc = apr1_md5( $passwd, $salt );
return( $hash eq $calc );
}
sub _have_module
t/06.apr1.t view on Meta::CPAN
};
subtest 'determinism for fixed salt' => sub
{
my $h1 = apr1_md5( 'secret', 'hfT7jp2q' );
my $h2 = apr1_md5( 'secret', 'hfT7jp2q' );
is( $h1, $h2, 'same password+salt => same hash' );
like( $h1, qr/\A\$apr1\$hfT7jp2q\$[.\/0-9A-Za-z]{22}\z/, 'hash contains given salt' );
};
subtest 'verify positive/negative' => sub
{
my $h = apr1_md5( 'opensesame', 'AB12.Cd/' );
ok( verify_apr1( 'opensesame', $h ), 'verify succeeds on correct password' );
ok( !verify_apr1( 'wrong', $h ), 'verify fails on wrong password' );
ok( !verify_apr1( 'opensesame', '$apr1$bad*salt$xxxxxxxxxxxxxxxxxxxxxx' ), 'rejects invalid salt chars' );
ok( !verify_apr1( 'opensesame', '$apr1$short$too_short' ), 'rejects invalid body length' );
};
subtest 'random salt uniqueness' => sub
{
my %seen;
my $collisions = 0;
for( 1..50 )
{
# random salt
my $h = apr1_md5( 'samepass' );
t/06.apr1.t view on Meta::CPAN
SKIP:
{
skip( 'Crypt::PasswdMD5 not installed', scalar( @cases ) ) unless( $HAVE_REF );
for my $c ( @cases )
{
my( $pw, $salt ) = @$c;
my $mine = apr1_md5( $pw, $salt );
my $ref = Crypt::PasswdMD5::apache_md5_crypt( $pw, $salt );
is( $mine, $ref, "matches reference for pw=[${pw}] salt=[$salt]" );
ok( verify_apr1( $pw, $mine ), 'verify_apr1 accepts our own output' );
}
};
};
subtest 'bcrypt make + matches' => sub
{
my $have_any = $have_bcrypt_crypt || $have_bcrypt_fallback;
SKIP:
{
unless( $have_any )
t/06.apr1.t view on Meta::CPAN
my $pw = "correct horse battery staple";
my $ht = $api->htpasswd( $pw, create => 1, algo => 'bcrypt', bcrypt_cost => $bcrypt_cost );
ok( $ht, 'constructed bcrypt object' );
my $hash = $ht->hash;
like( $hash, qr/^\$2[aby]\$\d{2}\$[A-Za-z0-9.\/]{22}[A-Za-z0-9.\/]{31}\z/, 'bcrypt hash format' );
ok( $ht->matches( $pw ), 'matches() true for bcrypt' );
# Re-wrap existing hash and verify again
my $ht2 = $api->htpasswd( $hash );
ok( $ht2->matches( $pw ), 're-wrapped bcrypt hash verifies' );
};
};
subtest 'sha256 ($5$) make + matches' => sub
{
my $have_any = $have_sha256_crypt || $have_sha_fallback;
SKIP:
{
t/92.signature.t view on Meta::CPAN
#!/usr/bin/perl
use Test2::V0;
# use Test2::Tools::Basic;
if (!$ENV{AUTHOR_TESTING}) {
skip_all( "Set the environment variable AUTHOR_TESTING to enable this test." );
}
elsif (!eval { require Module::Signature; 1 }) {
skip_all( "Next time around, consider installing Module::Signature, ".
"so you can verify the integrity of this distribution." );
}
elsif ( !-e 'SIGNATURE' )
{
skip_all( "SIGNATURE not found" );
}
elsif ( -s 'SIGNATURE' == 0 ) {
skip_all( "SIGNATURE file empty" );
}
elsif (!eval { require Socket; Socket::inet_aton('keyserver.ubuntu.com') }) {
skip_all( "Cannot connect to the keyserver to check module signature" );
}
else {
plan tests => 1;
}
my $ret = Module::Signature::verify();
SKIP: {
skip "Module::Signature cannot verify", 1
if $ret eq Module::Signature::CANNOT_VERIFY();
cmp_ok $ret, '==', Module::Signature::SIGNATURE_OK(), "Valid signature";
}
done_testing();
__END__
t/lib/Test/Apache2/API.pm view on Meta::CPAN
use HTTP::Request;
my $hostport = Apache::TestRequest::hostport( $config ) || '';
my( $host, $port ) = split( ':', ( $hostport ) );
my $mp_host = 'www.example.org';
Apache::TestRequest::user_agent(reset => 1, keep_alive => 1 );
my $ua = Apache::TestRequest->new;
# To get the fingerprint for the certificate in ./t/server.crt, do:
# echo "sha1\$$(openssl x509 -noout -in ./t/server.crt -fingerprint -sha1|perl -pE 's/^.*Fingerprint=|(\w{2})(?:\:?|$)/$1/g')"
$ua->ssl_opts(
# SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
# SSL_verify_mode => 0x00
# verify_hostname => 0,
SSL_fingerprint => 'sha1$DEE8650E44870896E821AAE4A5A24382174D100E',
# SSL_version => 'SSLv3',
# SSL_verfifycn_name => 'localhost',
);
my $req = HTTP::Request->new( 'GET' => "${proto}://${hostport}/tests/api/some_method" );
my $resp = $ua->request( $req );
is( $resp->code, Apache2::Const::HTTP_OK, 'some test name' );
=head1 VERSION
t/lib/Test/Apache2/API/Request.pm view on Meta::CPAN
=head1 SYNOPSIS
my $hostport = Apache::TestRequest::hostport( $config ) || '';
my( $host, $port ) = split( ':', ( $hostport ) );
my $mp_host = 'www.example.org';
Apache::TestRequest::user_agent(reset => 1, keep_alive => 1 );
my $ua = Apache::TestRequest->new;
# To get the fingerprint for the certificate in ./t/server.crt, do:
# echo "sha1\$$(openssl x509 -noout -in ./t/server.crt -fingerprint -sha1|perl -pE 's/^.*Fingerprint=|(\w{2})(?:\:?|$)/$1/g')"
$ua->ssl_opts(
# SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
# SSL_verify_mode => 0x00
# verify_hostname => 0,
SSL_fingerprint => 'sha1$DEE8650E44870896E821AAE4A5A24382174D100E',
# SSL_version => 'SSLv3',
# SSL_verfifycn_name => 'localhost',
);
my $req = HTTP::Request->new( 'GET' => "${proto}://${hostport}/tests/request/some_method" );
my $resp = $ua->request( $req );
is( $resp->code, Apache2::Const::HTTP_OK, 'some test name' );
=head1 VERSION
t/lib/Test/Apache2/API/Response.pm view on Meta::CPAN
=head1 SYNOPSIS
my $hostport = Apache::TestRequest::hostport( $config ) || '';
my( $host, $port ) = split( ':', ( $hostport ) );
my $mp_host = 'www.example.org';
Apache::TestRequest::user_agent(reset => 1, keep_alive => 1 );
my $ua = Apache::TestRequest->new;
# To get the fingerprint for the certificate in ./t/server.crt, do:
# echo "sha1\$$(openssl x509 -noout -in ./t/server.crt -fingerprint -sha1|perl -pE 's/^.*Fingerprint=|(\w{2})(?:\:?|$)/$1/g')"
$ua->ssl_opts(
# SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
# SSL_verify_mode => 0x00
# verify_hostname => 0,
SSL_fingerprint => 'sha1$DEE8650E44870896E821AAE4A5A24382174D100E',
# SSL_version => 'SSLv3',
# SSL_verfifycn_name => 'localhost',
);
my $req = HTTP::Request->new( 'GET' => "${proto}://${hostport}/tests/response/some_method" );
my $resp = $ua->request( $req );
is( $resp->code, Apache2::Const::HTTP_OK, 'some test name' );
=head1 VERSION
( run in 1.182 second using v1.01-cache-2.11-cpan-39bf76dae61 )