Net-SAML2
view release on metacpan or search on metacpan
lib/Net/SAML2/Binding/Redirect.pm view on Meta::CPAN
elsif ($self->param eq 'SAMLResponse') {
croak("Need to have a cert specified") unless $self->has_cert;
}
}
# BUILDARGS
# Earlier versions expected the cert to be a string. However, metadata
# can include multiple signing certificates so the $idp->cert is now
# expected to be an arrayref to the certificates. To avoid breaking existing
# applications this changes the the cert to an arrayref if it is not
# already an array ref.
around BUILDARGS => sub {
my $orig = shift;
my $self = shift;
my %params = @_;
if ($params{cert} && ref($params{cert}) ne 'ARRAY') {
$params{cert} = [$params{cert}];
}
return $self->$orig(%params);
};
sub get_redirect_uri {
my $self = shift;
my $request = shift;
if (!defined $request) {
croak("Unable to create redirect URI without a request");
}
my $relaystate = shift;
my $input = "$request";
my $output = '';
rawdeflate \$input => \$output;
my $req = encode_base64($output, '');
my $uri = URI->new($self->url);
$uri->query_param($self->param, $req);
$uri->query_param('RelayState', $relaystate) if defined $relaystate;
return $uri->as_string if $self->insecure;
return $self->_sign_redirect_uri($uri);
}
sub _sign_redirect_uri {
my $self = shift;
my $uri = shift;
my $key_string = read_text($self->key);
my $pk = Crypt::PK::RSA->new();
my $rsa_priv = $pk->import_key(\$key_string);
$uri->query_param('SigAlg',
$self->sig_hash eq 'sha1'
? 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
: 'http://www.w3.org/2001/04/xmldsig-more#rsa-' . $self->sig_hash);
my $to_sign = $uri->query;
my $sig = encode_base64($rsa_priv->sign_message($to_sign, uc($self->sig_hash), 'v1.5'), '');
$uri->query_param('Signature', $sig);
return $uri->as_string;
}
sub sign {
my $self = shift;
if ($self->insecure) {
croak("Cannot sign an insecure request!");
}
return $self->get_redirect_uri(@_);
}
sub verify {
my $self = shift;
my $query_string = shift;
$query_string =~ s#^.*\?##;
my %params = map { split(/=/, $_, 2) } split(/&/, $query_string);
my $sigalg = uri_unescape($params{SigAlg});
my $encoded_sig = uri_unescape($params{Signature});
my $sig = decode_base64($encoded_sig);
my @signed_parts;
for my $p ($self->param, qw(RelayState SigAlg)) {
push @signed_parts, join('=', $p, $params{$p}) if exists $params{$p};
}
my $signed = join('&', @signed_parts);
$self->_verify($sigalg, $signed, $sig);
# unpack the SAML request
my $deflated = decode_base64(uri_unescape($params{$self->param}));
my $request = '';
rawinflate \$deflated => \$request;
# return the relaystate if it is defined
return ($request, defined $params{RelayState} ? uri_unescape($params{RelayState}) : undef);
}
sub _verify {
my ($self, $sigalg, $signed, $sig) = @_;
foreach my $crt (@{$self->cert}) {
my $cert = Crypt::OpenSSL::X509->new_from_string($crt);
my $pk = Crypt::PK::RSA->new();
my $rsa_pub = $pk->import_key(\$cert->pubkey);
my $hash_name;
if ($sigalg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') {
$hash_name = 'SHA256';
} elsif ($sigalg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224') {
$hash_name = 'SHA224';
} elsif ($sigalg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384') {
$hash_name = 'SHA384';
} elsif ($sigalg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512') {
$hash_name = 'SHA512';
} elsif ($sigalg eq 'http://www.w3.org/2000/09/xmldsig#rsa-sha1') {
$hash_name = 'SHA1';
}
else {
warn "Unsupported Signature Algorithim: $sigalg, defaulting to sha256" if $self->debug;
}
return 1 if $rsa_pub->verify_message($sig, $signed, $hash_name, 'v1.5');
warn "Unable to verify with " . $cert->subject if $self->debug;
}
croak("Unable to verify the XML signature");
}
__PACKAGE__->meta->make_immutable;
__END__
=pod
=encoding UTF-8
=head1 NAME
Net::SAML2::Binding::Redirect - HTTP Redirect binding for SAML
=head1 VERSION
version 0.85
=head1 SYNOPSIS
my $redirect = Net::SAML2::Binding::Redirect->new(
key => '/path/to/SPsign-nopw-key.pem', # Service Provider (SP) private key
url => $sso_url, # Service Provider Single Sign Out URL
param => 'SAMLRequest' OR 'SAMLResponse', # Type of request
cert => $idp->cert('signing') # Identity Provider (IdP) certificate
sig_hash => 'sha256', 'sha224', 'sha384', 'sha512' or 'sha1' # Signature to sign request
);
my $url = $redirect->sign($authnreq);
my $ret = $redirect->verify($url);
=head1 METHODS
=head2 new( ... )
Constructor. Creates an instance of the Redirect binding.
Arguments:
=over
=item B<key>
The SP's (Service Provider) also known as your application's signing key
that your application uses to sign the AuthnRequest. Some IdPs may not
verify the signature.
( run in 0.685 second using v1.01-cache-2.11-cpan-ceb78f64989 )