Postini-SAML
view release on metacpan - search on metacpan
view release on metacpan or search on metacpan
lib/Postini/SAML.pm view on Meta::CPAN
package Postini::SAML;
{
$Postini::SAML::VERSION = '0.001';
}
use warnings;
use strict;
use Crypt::OpenSSL::RSA;
use MIME::Base64 qw( encode_base64 );
use XML::Spice;
use Date::Format qw( time2str );
use Data::Random qw( rand_chars );
use XML::CanonicalizeXML;
use Digest::SHA1 qw( sha1 );
use Carp qw( croak );
# Postini SAML ACS
my $ACS_URL = 'https://pfs.postini.com/pfs/spServlet';
sub get_acs_url {
return $ACS_URL;
}
sub new {
my ($class, $arg) = @_;
my @missing = grep { not exists $arg->{$_} } qw( keyfile certfile issuer );
if ( @missing )
{
croak "missing args: " . join( q{ }, @missing );
}
my $self = bless {}, $class;
$self->_load_rsa_key( $arg->{'keyfile'}, $arg->{'certfile'} );
$self->{'issuer'} = $arg->{'issuer'};
return $self;
}
sub _load_rsa_key {
my ($self, $key_file, $cert_file) = @_;
# load the keyfile and prepare a context for signing
open my $key_fh, '<', $key_file or croak "couldn't open $key_file for reading: $!";
my $key_text = do { local $/; <$key_fh> };
close $key_fh;
my $key = Crypt::OpenSSL::RSA->new_private_key( $key_text );
if ( not $key )
{
croak "failed to instantiate Crypt::OpenSSL::RSA object from $key_file";
}
$key->use_pkcs1_padding();
$self->{'key'} = $key;
# we need to include the certificate without headers in the signed XML, so
# extract it
open my $cert_fh, '<', $cert_file or croak "couldn't open $cert_file for reading: $!";
my $cert_text = do { local $/; <$cert_fh> };
close $cert_fh;
my ($cert_pem) = $cert_text =~ m{
-----BEGIN\sCERTIFICATE-----
(.+)
-----END\sCERTIFICATE-----
}smx;
$cert_pem =~ s{ [\r\n]+ }{}smxg;
# build a XML fragment containing the key info. this will be included in
# the signature XML
$self->{'key_info_xml'} =
x('ds:KeyInfo',
x('ds:X509Data',
x('ds:X509Certificate', $cert_pem),
),
),
;
}
# return the current signature xml (actually XML::Spice chunk). deliberately
# returns undef if its not available, causing it to be ignored during chunk
# expansion
sub _get_cached_signature_xml {
my ($self) = @_;
return $self->{'signature_xml'};
}
# generate a valid, signed response and return it
sub get_response_xml {
my ($self, $mail) = @_;
if ( not $mail )
{
croak "required email address not provided";
}
# INPUT:
# T, text-to-be-signed, a byte string;
# Ks, RSA private key;
#
# 1. Canonicalize the text-to-be-signed, C = C14n(T).
# 2. Compute the message digest of the canonicalized text, m = Hash(C).
# 3. Encapsulate the message digest in an XML <SignedInfo> element, SI, in canonicalized form.
# 4. Compute the RSA signatureValue of the canonicalized <SignedInfo> element, SV = RsaSign(Ks, SI).
# 5. Compose the final XML document including the signatureValue, this time in non-canonicalized form.
# get rid of any cached signature
view all matches for this distributionview release on metacpan - search on metacpan
( run in 0.635 second using v1.00-cache-2.02-grep-82fe00e-cpan-2cc899e4a130 )