File Coverage

blib/lib/Net/SAML2/Role/VerifyXML.pm
Criterion Covered Total %
statement 48 51 94.1
branch 15 18 83.3
condition 3 3 100.0
subroutine 11 12 91.6
pod 1 1 100.0
total 78 85 91.7


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