Net-SAML2

 view release on metacpan or  search on metacpan

t/16-encrypted-assertion.t  view on Meta::CPAN

use strict;
use warnings;

use Test::Lib;
use Test::Net::SAML2;

use Net::SAML2::Protocol::Assertion;
use XML::Sig;
use MIME::Base64 qw/decode_base64/;

my $response = <<'RESPONSE';
PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIERlc3RpbmF0aW9uPSJodHRwczovL25ldHNhbWwyLXRlc3RhcHAubG9jYWwvY29uc3VtZXItcG9zdCIgSUQ9IklEXzZhNj...
RESPONSE

my $encryptedresponse = $response;

my $sp = net_saml2_sp();

$sp->{cacert} = 't/keycloak-cacert.pem';

my $post = $sp->post_binding;

my $subject;

lives_ok(
    sub {
        $subject = $post->handle_response($response);
    },
    '$sp->handle_response works'
);

# Trust-anchor enforcement on the encrypted-assertion path.
#
# Without a cacert configured on new_from_xml,
# _verify_encrypted_assertion previously short-circuited and accepted
# the KeyInfo-embedded signing certificate. new_from_xml now refuses
# unless the caller explicitly opts out via insecure_trust_embedded_cert.

throws_ok(sub {
    Net::SAML2::Protocol::Assertion->new_from_xml(
        xml      => decode_base64($response),
        key_file => 't/encrypted-sign-private.pem',
        # no cacert
    );
}, qr/'cacert' or 'cert_text' is required to verify/, 'encrypted assertion without cacert croaks');

lives_ok(sub {
    Net::SAML2::Protocol::Assertion->new_from_xml(
        xml                      => decode_base64($response),
        key_file                 => 't/encrypted-sign-private.pem',
        insecure_trust_embedded_cert => 1,
    );
}, 'explicit insecure_trust_embedded_cert opt-out lets encrypted assertion through');

# require_signed_assertion: when set, the decrypted assertion must
# carry a <dsig:Signature>. The existing fixture is a signed encrypted
# assertion, so this is the positive case (does not regress).
lives_ok(sub {
    Net::SAML2::Protocol::Assertion->new_from_xml(
        xml                      => decode_base64($response),
        key_file                 => 't/encrypted-sign-private.pem',
        cacert                   => 't/keycloak-cacert.pem',
        require_signed_assertion => 1,
    );
}, 'require_signed_assertion accepts a properly signed encrypted assertion');

# Negative case (unsigned encrypted assertion + require_signed_assertion
# => 1 should croak) would need an unsigned-encrypted-assertion fixture
# that is not present in this test data. To be added when such a
# fixture lands; the code path is the one above with the new croak.

my $assertion = Net::SAML2::Protocol::Assertion->new_from_xml(
                        xml => decode_base64($response),
                        key_file => 't/encrypted-sign-private.pem',
                        cacert => 't/keycloak-cacert.pem',
                        );

isa_ok($assertion, 'Net::SAML2::Protocol::Assertion');

is($assertion->in_response_to, 'NETSAML2_935c782d5f5e499638a7471b257062b5');

is(scalar keys %{ $assertion->attributes }, 4);
is(scalar @{ $assertion->attributes->{EmailAddress} }, 1);

is($assertion->session, '91af7e38-e3a6-4be4-9d91-04a32c2ddee2::29499342-7453-4345-b702-68351fcad4f2', 'Session ID is correct');
is($assertion->nameid,  'timlegge@cpan.org', 'Name ID is correct');

cmp_deeply(
    $assertion->attributes,
    {
        EmailAddress => [qw(timlegge@cpan.org)],
        CN           => [qw(keycloak.local)],
        FirstName    => [qw(Timothy)],
        Role         => [qw(manage-account)],
    },
    "Assertion attributes are ok"
);

isa_ok($assertion->not_before, 'DateTime');
isa_ok($assertion->not_after,  'DateTime');

is($assertion->audience, 'https://netsaml2-testapp.local', "Assertion audience is ct.local");
is($assertion->valid('foo'),             0, "foo isn't a valid assertion");
is($assertion->valid('ct.local'), 0, "ct.local isn't valid either");

# fudge validity times to test valid()
$assertion->{not_before} = DateTime->now;
$assertion->{not_after} = DateTime->now->add(minutes => 15);
is($assertion->valid('https://netsaml2-testapp.local'), 1, "https://netsaml2-testapp.local is valid now - InResponseTo not Checked");
is($assertion->valid('https://netsaml2-testapp.local', 'NETSAML2_935c782d5f5e499638a7471b257062b5'), 1, "https://netsaml2-testapp.local is valid now - InResponseTo Checked");
is($assertion->valid('https://netsaml2-testapp.local', 'NETSAML2_935c782d5f5e499638a7471b257062'), 0, "Invalid InResponseTo Checked and failed");

$assertion->{not_before} = DateTime->now->add(minutes => 5);
is($assertion->valid('http://ct.local'), 0, "and invalid again - InResponseTo not Checked");
is($assertion->valid('http://ct.local', 'N3k95Hg41WCHdwc9mqXynLPhB'), 0, "and invalid again - InResponseTo Checked");



( run in 0.941 second using v1.01-cache-2.11-cpan-5fbc6bb55f2 )