diff --git a/Makefile.PL b/Makefile.PL index 783ee4d..9ba1751 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -49,7 +49,7 @@ my %WriteMakefileArgs = ( "URI::Escape" => 0, "URI::QueryParam" => 0, "URN::OASIS::SAML2" => "0.003", - "XML::Enc" => "0.12", + "XML::Enc" => "0.13", "XML::Generator" => "1.13", "XML::LibXML" => 0, "XML::LibXML::XPathContext" => 0, @@ -131,7 +131,7 @@ my %FallbackPrereqs = ( "URI::QueryParam" => 0, "URI::URL" => 0, "URN::OASIS::SAML2" => "0.003", - "XML::Enc" => "0.12", + "XML::Enc" => "0.13", "XML::Generator" => "1.13", "XML::LibXML" => 0, "XML::LibXML::XPathContext" => 0, diff --git a/cpanfile b/cpanfile index 2f34536..dafa383 100644 --- a/cpanfile +++ b/cpanfile @@ -33,7 +33,7 @@ requires "URI::Encode" => "0"; requires "URI::Escape" => "0"; requires "URI::QueryParam" => "0"; requires "URN::OASIS::SAML2" => "0.003"; -requires "XML::Enc" => "0.12"; +requires "XML::Enc" => "0.13"; requires "XML::Generator" => "1.13"; requires "XML::LibXML" => "0"; requires "XML::LibXML::XPathContext" => "0"; diff --git a/dist.ini b/dist.ini index e9257c4..5171951 100644 --- a/dist.ini +++ b/dist.ini @@ -48,7 +48,7 @@ copy = cpanfile, Makefile.PL, README, LICENSE, CONTRIBUTORS skip = Saml2Test [Prereqs / RuntimeRequires] -XML::Enc = 0.12 +XML::Enc = 0.13 XML::Sig = 0.64 XML::Writer = 0.625 ; Here because otherwise only on test you get to pull in this dependency diff --git a/lib/Net/SAML2/Protocol/Assertion.pm b/lib/Net/SAML2/Protocol/Assertion.pm index 5f8b83a..89530f2 100644 --- a/lib/Net/SAML2/Protocol/Assertion.pm +++ b/lib/Net/SAML2/Protocol/Assertion.pm @@ -93,6 +93,50 @@ EncryptedAssertion is properly validated. =cut +sub _verify_encrypted_assertion { + my $self = shift; + my $xml = shift; + my $cacert = shift; + my $key_file = shift; + my $key_name = shift; + + my $xpath = XML::LibXML::XPathContext->new($xml); + $xpath->registerNs('saml', 'urn:oasis:names:tc:SAML:2.0:assertion'); + $xpath->registerNs('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol'); + $xpath->registerNs('dsig', 'http://www.w3.org/2000/09/xmldsig#'); + $xpath->registerNs('xenc', 'http://www.w3.org/2001/04/xmlenc#'); + + return $xml unless $xpath->exists('//saml:EncryptedAssertion'); + + croak "Encrypted Assertions require key_file" if !defined $key_file; + + $xml = $self->_decrypt( + $xml, + key_file => $key_file, + key_name => $key_name, + ); + $xpath->setContextNode($xml); + + my $assert_nodes = $xpath->findnodes('//saml:Assertion'); + return $xml unless $assert_nodes->size; + my $assert = $assert_nodes->get_node(1); + + return $xml unless $xpath->exists('dsig:Signature', $assert); + my $xml_opts->{ no_xml_declaration } = 1; + my $x = Net::SAML2::XML::Sig->new($xml_opts); + my $ret = $x->verify($assert->toString()); + die "Decrypted Assertion signature check failed" unless $ret; + + return $xml unless $cacert; + my $cert = $x->signer_cert; + die "Certificate not provided in SAML Response, cannot validate" unless $cert; + + my $ca = Crypt::OpenSSL::Verify->new($cacert, { strict_certs => 0 }); + die "Unable to verify signer cert with cacert: " . $cert->subject + unless $ca->verify($cert); + return $xml; +} + sub new_from_xml { my($class, %args) = @_; @@ -108,30 +152,12 @@ sub new_from_xml { my $xml = no_comments($args{xml}); $xpath->setContextNode($xml); - my $dom = $xml; - - if ($xpath->exists('//saml:EncryptedAssertion')) { - - croak "Encrypted Assertions require key_file" if !defined $key_file; - - my $assert = $xpath->findnodes('//saml:Assertion')->[0]; - my @signedinfo = $xpath->findnodes('dsig:Signature', $assert); - - if (defined $assert && (scalar @signedinfo ne 0)) { - my $xml_opts->{ no_xml_declaration } = 1; - my $x = Net::SAML2::XML::Sig->new($xml_opts); - my $ret = $x->verify($assert->serialize); - die "Decrypted Assertion signature check failed" unless $ret; - - return unless $cacert; - my $cert = $x->signer_cert - or die "Certificate not provided and not in SAML Response, cannot validate"; - - my $ca = Crypt::OpenSSL::Verify->new($cacert, { strict_certs => 0 }); - die "Unable to verify signer cert with cacert: " . $cert->subject - unless $ca->verify($cert); - } - } + $xml = $class->_verify_encrypted_assertion( + $xml, + $cacert, + $key_file, + $args{key_name}, + ); my $dec = $class->_decrypt( $xml,