File Coverage

blib/lib/Net/SAML2/Role/VerifyXML.pm
Criterion Covered Total %
statement 47 50 94.0
branch 15 18 83.3
condition 3 3 100.0
subroutine 11 12 91.6
pod 1 1 100.0
total 77 84 91.6


line stmt bran cond sub pod time code
1             package Net::SAML2::Role::VerifyXML;
2 26     26   17900 use Moose::Role;
  26         9430  
  26         267  
3             our $VERSION = '0.74'; # VERSION
4              
5 26     26   149447 use Net::SAML2::XML::Sig;
  26         70  
  26         196  
6 26     26   1252 use Crypt::OpenSSL::Verify;
  26         79  
  26         662  
7 26     26   152 use Crypt::OpenSSL::X509;
  26         61  
  26         1152  
8 26     26   162 use Carp qw(croak);
  26         71  
  26         1422  
9 26     26   225 use List::Util qw(none);
  26         103  
  26         1617  
10 26     26   255 use Try::Tiny;
  26         59  
  26         12599  
11              
12             # ABSTRACT: A role to verify the SAML response XML
13              
14              
15              
16              
17             sub verify_xml {
18 13     13 1 14035 my $self = shift;
19 13         27 my $xml = shift;
20 13         52 my %args = @_;
21              
22 13         81 my $cacert = delete $args{cacert};
23 13         30 my $anchors = delete $args{anchors};
24              
25 13         368 my $x = Net::SAML2::XML::Sig->new({
26             x509 => 1,
27             exclusive => 1,
28             %args,
29             });
30              
31 13 100       920 croak("XML signature check failed") unless $x->verify($xml);
32              
33 12 100 100     22289 return if !$anchors && !$cacert;
34              
35 10 50       113 my $cert = $x->signer_cert
36             or die "Certificate not provided in SAML Response, cannot validate\n";
37              
38 10 100       235 if ($cacert) {
39 5         1454 my $ca = Crypt::OpenSSL::Verify->new($cacert, { strict_certs => 0 });
40 5     5   731 try { $ca->verify($cert) }
41             catch {
42 0     0   0 croak("Could not verify CA certificate: $_");
43 5         92 };
44             }
45              
46 10 100       1302 return if !$anchors;
47              
48 5 50       19 if (ref $anchors ne 'HASH') {
49 0         0 croak("Unable to verify anchor trust");
50             }
51              
52 5         16 my ($key) = keys %$anchors;
53 5 50   8   32 if (none { $key eq $_ } qw(subject issuer issuer_hash)) {
  8         24  
54 0         0 croak("Unable to verify anchor trust, requires subject, issuer or issuer_hash");
55             }
56              
57 5         40 my $got = $cert->$key;
58 5         99 my $want = $anchors->{$key};
59 5 100       19 if (!ref $want) {
60 3         8 $want = [ $want ];
61             }
62              
63 5 100   5   23 if (none { $_ eq $got } @$want) {
  5         18  
64 1         24 croak("Could not verify trust anchors of certificate!");
65             }
66 4         26 return;
67              
68             }
69              
70              
71             1;
72              
73             __END__
74              
75             =pod
76              
77             =encoding UTF-8
78              
79             =head1 NAME
80              
81             Net::SAML2::Role::VerifyXML - A role to verify the SAML response XML
82              
83             =head1 VERSION
84              
85             version 0.74
86              
87             =head1 SYNOPSIS
88              
89             use Net::SAML2::Some::Module;
90              
91             use Moose;
92             with 'Net::SAML2::Role::VerifyXML';
93              
94             sub do_something_with_xml {
95             my $self = shift;
96             my $xml = shift;
97              
98             $self->verify_xml($xml,
99             # Most of these options are passed to Net::SAML2::XML::Sig, except for the
100             # cacert
101             # Most options are optional
102             cacert => $self->cacert,
103             cert_text => $self->cert,
104             no_xml_declaration => 1,
105             );
106             }
107              
108             =head1 DESCRIPTION
109              
110             =head1 METHODS
111              
112             =head2 verify_xml($xml, %args)
113              
114             $self->verify_xml($xml,
115             # Most of these options are passed to Net::SAML2::XML::Sig, except for the
116             # cacert
117             # Most options are optional
118             cert_text => $self->cert,
119             no_xml_declaration => 1,
120              
121             # Used for a trust model, if lacking, everything is trusted
122             cacert => $self->cacert,
123             # or check specific certificates based on subject/issuer or issuer hash
124             anchors => {
125             # one of the following is allowed
126             subject => ["subject a", "subject b"],
127             issuer => ["Issuer A", "Issuer B"],
128             issuer_hash => ["Issuer A hash", "Issuer B hash"],
129             },
130             );
131              
132             =head1 AUTHORS
133              
134             =over 4
135              
136             =item *
137              
138             Chris Andrews <chrisa@cpan.org>
139              
140             =item *
141              
142             Timothy Legge <timlegge@gmail.com>
143              
144             =back
145              
146             =head1 COPYRIGHT AND LICENSE
147              
148             This software is copyright (c) 2023 by Venda Ltd, see the CONTRIBUTORS file for others.
149              
150             This is free software; you can redistribute it and/or modify it under
151             the same terms as the Perl 5 programming language system itself.
152              
153             =cut