Skip to content

Commit 6d1b058

Browse files
authored
Merge pull request #57 from timlegge/encrypted-assertions
Initial Working EncryptedAssertion support
2 parents 34a432c + bff02f7 commit 6d1b058

File tree

11 files changed

+264
-5
lines changed

11 files changed

+264
-5
lines changed

Makefile.PL

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ my %WriteMakefileArgs = (
4141
"URI" => 0,
4242
"URI::Encode" => 0,
4343
"URI::QueryParam" => 0,
44+
"XML::Enc" => "0.03",
4445
"XML::Generator" => 0,
4546
"XML::LibXML" => 0,
47+
"XML::LibXML::XPathContext" => 0,
4648
"XML::Sig" => "0.52",
4749
"XML::Writer" => "0.625",
4850
"base" => 0,
@@ -66,7 +68,7 @@ my %WriteMakefileArgs = (
6668
"URI::URL" => 0,
6769
"XML::LibXML::XPathContext" => 0
6870
},
69-
"VERSION" => "0.53",
71+
"VERSION" => "0.54",
7072
"test" => {
7173
"TESTS" => "t/*.t t/author/*.t"
7274
}
@@ -111,6 +113,7 @@ my %FallbackPrereqs = (
111113
"URI::Encode" => 0,
112114
"URI::QueryParam" => 0,
113115
"URI::URL" => 0,
116+
"XML::Enc" => "0.03",
114117
"XML::Generator" => 0,
115118
"XML::LibXML" => 0,
116119
"XML::LibXML::XPathContext" => 0,

README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ NAME
22
Net::SAML2 - SAML2 bindings and protocol implementation
33

44
VERSION
5-
version 0.53
5+
version 0.54
66

77
SYNOPSIS
88
See TUTORIAL.md for implementation documentation and

cpanfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ requires "MooseX::Types::URI" => "0";
2525
requires "URI" => "0";
2626
requires "URI::Encode" => "0";
2727
requires "URI::QueryParam" => "0";
28+
requires "XML::Enc" => "0.03";
2829
requires "XML::Generator" => "0";
2930
requires "XML::LibXML" => "0";
31+
requires "XML::LibXML::XPathContext" => "0";
3032
requires "XML::Sig" => "0.52";
3133
requires "XML::Writer" => "0.625";
3234
requires "base" => "0";

dist.ini

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,52 @@ copy = cpanfile, Makefile.PL, README
5050
[AutoPrereqs]
5151
skip = Saml2Test
5252

53-
[Prereqs]
53+
[Prereqs / RuntimeRequires]
5454
Crypt::OpenSSL::Bignum = 0
55+
Crypt::OpenSSL::Random = 0
56+
Crypt::OpenSSL::RSA = 0
57+
Crypt::OpenSSL::Verify = 0
58+
Crypt::OpenSSL::X509 = 0
59+
DateTime = 0
60+
DateTime::Format::XSD = 0
61+
DateTime::HiRes = 0
62+
Exporter = 0
63+
File::Slurper = 0
64+
HTTP::Request::Common = 0
65+
IO::Compress::RawDeflate = 0
66+
IO::Uncompress::RawInflate = 0
67+
List::Util = 0
68+
LWP::Protocol::https = 0
69+
LWP::UserAgent = 0
70+
MIME::Base64 = 0
71+
Moose = 0
72+
Moose::Role = 0
73+
MooseX::Types::Common::String = 0
74+
MooseX::Types::DateTime = 0
75+
MooseX::Types::URI = 0
76+
namespace::autoclean = 0
77+
URI = 0
78+
URI::Encode = 0
79+
URI::QueryParam = 0
80+
XML::Enc = 0.05
81+
XML::Generator = 0
82+
XML::LibXML = 0
83+
XML::LibXML::XPathContext = 0
5584
XML::Sig = 0.52
85+
XML::Writer = 0.625
86+
87+
[Prereqs / TestRequires]
88+
Import::Into = 0
89+
Path::Tiny = 0
90+
URI::URL = 0
91+
Test::Deep = 0
92+
Test::Exception = 0
93+
Test::Fatal = 0
94+
Test::Lib = 0
95+
Test::More = 0
96+
Test::NoTabs = 0
97+
Test::Pod = 1.14
98+
Test::Pod::Coverage = 1.04
5699

57100
[MetaJSON]
58101
[MetaProvides::Package]

lib/Net/SAML2.pm

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ Net::SAML2 - SAML bindings and protocol implementation
7171
7272
if ($ret) {
7373
my $assertion = Net::SAML2::Protocol::Assertion->new_from_xml(
74-
xml => decode_base64($saml_response)
74+
xml => decode_base64($saml_response),
75+
key_file => "SP-Private-Key.pem", # Required for EncryptedAssertions
76+
cacert => "IdP-cacert.pem", # Required for EncryptedAssertions
7577
);
7678
7779
# ...
@@ -102,6 +104,9 @@ Identity Providers (IdPs). It has been tested against:
102104
103105
=item PingIdentity
104106
107+
Version 0.54 and newer support EncryptedAssertions. No changes required to existing
108+
SP applications if EncryptedAssertions are not in use.
109+
105110
=back
106111
107112
=head1 MAJOR CAVEATS

lib/Net/SAML2/Protocol/Assertion.pm

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use DateTime;
88
use DateTime::HiRes;
99
use DateTime::Format::XSD;
1010
use Net::SAML2::XML::Util qw/ no_comments /;
11+
use Net::SAML2::XML::Sig;
12+
use XML::Enc;
1113
use XML::LibXML;
1214

1315
with 'Net::SAML2::Role::ProtocolMessage';
@@ -55,6 +57,22 @@ Arguments:
5557
5658
XML data
5759
60+
=item B<key_file>
61+
62+
Optional but Required handling Encrypted Assertions.
63+
64+
path to the SP's private key file that matches the SP's public certificate
65+
used by the IdP to Encrypt the response (or parts of the response)
66+
67+
=item B<cacert>
68+
69+
path to the CA certificate for verification. Optional: This is only used for
70+
validating the certificate provided for a signed Assertion that was found
71+
when the EncryptedAssertion is decrypted.
72+
73+
While optional it is recommended for ensuring that the Assertion in an
74+
EncryptedAssertion is properly validated.
75+
5876
=back
5977
6078
=cut
@@ -63,12 +81,50 @@ sub new_from_xml {
6381
my($class, %args) = @_;
6482

6583
my $dom = no_comments($args{xml});
84+
my $key_file = $args{key_file};
85+
my $cacert = $args{cacert};
6686

6787
my $xpath = XML::LibXML::XPathContext->new($dom);
6888
$xpath->registerNs('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
6989
$xpath->registerNs('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
90+
$xpath->registerNs('xenc', 'http://www.w3.org/2001/04/xmlenc#');
7091

7192
my $attributes = {};
93+
94+
if ($xpath->findnodes('//saml:EncryptedAssertion')) {
95+
if ( ! defined $key_file) {
96+
die "Encrypted Assertions require key_file";
97+
}
98+
my $decrypted;
99+
my $enc = XML::Enc->new(
100+
{ key => $key_file , no_xml_declaration => 1 }, );
101+
$decrypted = $enc->decrypt($dom->toString());
102+
$dom = XML::LibXML->load_xml(string => $decrypted);
103+
$xpath = XML::LibXML::XPathContext->new($dom);
104+
$xpath->registerNs('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
105+
$xpath->registerNs('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
106+
$xpath->registerNs('xenc', 'http://www.w3.org/2001/04/xmlenc#');
107+
108+
my $xml_opts->{ no_xml_declaration } = 1;
109+
110+
my $assert = $xpath->findnodes('//saml:Assertion')->[0];
111+
if (defined $assert) {
112+
my $x = Net::SAML2::XML::Sig->new($xml_opts);
113+
my $ret = $x->verify($assert->serialize);
114+
die "Decrypted Assertion signature check failed" unless $ret;
115+
116+
if ($cacert) {
117+
my $cert = $x->signer_cert
118+
or die "Certificate not provided and not in SAML Response, cannot validate";
119+
120+
my $ca = Crypt::OpenSSL::Verify->new($cacert, { strict_certs => 0, });
121+
if (! $ca->verify($cert)) {
122+
die "Decrypted Assertion - Unable to verify signer cert with cacert: $cert->subject";
123+
}
124+
}
125+
}
126+
}
127+
72128
for my $node (
73129
$xpath->findnodes('//saml:Assertion/saml:AttributeStatement/saml:Attribute'))
74130
{

t/16-encrypted-assertion.t

Lines changed: 78 additions & 0 deletions
Large diffs are not rendered by default.

t/encrypted-sign-private.pem

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-----BEGIN PRIVATE KEY-----
2+
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
51+
GH7LFqPBJcO0cWiRKpb2IHyGiMFO/lwQ
52+
-----END PRIVATE KEY-----

t/keycloak-cacert.pem

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICnTCCAYUCBgF5YqtQBTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdGb3N3
3+
aWtpMB4XDTIxMDUxMjIyMTkyNFoXDTMxMDUxMjIyMjEwNFowEjEQMA4GA1UEAwwH
4+
Rm9zd2lraTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJMGG6jrdadw
5+
/6rnOAGmNtmdIZy116JyocKlsoxg+iQTlRI2e3gelsiOW7rXNIYHH/f4ozQ8F4ba
6+
7GxJMNWlrDJFN23Dij521PVqJHsu3ZA8JOP+txMCN22zhCO6OYiWx5P9wm7zWVcf
7+
g3sS9564LQ4M7JBQ8tDYxY9RLCDR+sNNd0hWm6SrkEyghqbcxNY+rgXfxLBK5eGX
8+
yX1Zk0NLA5XqRg5a8BDz1oUZ6O4c21tVOvV8vqCUtcnx3hWxcBgXizW8pkSQpQiQ
9+
96zXquAvDwkLtYnQLV5GQlt6c414A7U4dsAZZCc490rqncfsjDfbFMzj89s/WCtF
10+
DOzSa163pqECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPpeGsBOJN3xGUvtxJqPM
11+
2ja3g7G7LiOJGvzZSIOFr50baebsoJNRwL2GDfYUTM1SWDz4UHnGebsme5TTmzjV
12+
O3YEvnOMTtVC6/fYYdouAqIJ+cTmmF3Cxd/tOr5fkaPscB0x0+zqWqgBZLo0FVEC
13+
DMt+DYk1HaQJPxsAXGahUmIIpfIKO7AUx5tD74PR8XeHWyL0w8jg1h8nVtc49P7h
14+
08SzmSFY0phJ9plLpSubCsd/1KMPOJ0Dh7kYEaOJOOWwjLggiho5N4KBytpts6HI
15+
jmPlKvV7UJEAmQykuhO6PyFfGjwXxpYRTtGa3fZQqu6BztRHDSZQfc+K08VTmAjr
16+
iw==
17+
-----END CERTIFICATE-----

xt/testapp/lib/Saml2Test.pm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ post '/consumer-post' => sub {
143143

144144
if ($ret) {
145145
my $assertion = Net::SAML2::Protocol::Assertion->new_from_xml(
146-
xml => decode_base64(params->{SAMLResponse})
146+
xml => decode_base64(params->{SAMLResponse}),
147+
key_file => config->{key},
148+
cacert => config->{cacert},
147149
);
148150

149151
template 'user', { assertion => $assertion };

0 commit comments

Comments
 (0)