Net-SPID
view release on metacpan or search on metacpan
lib/Net/SPID/SAML/In/Response.pm view on Meta::CPAN
my $classref = $_[0]->xpath->findvalue('/samlp:Response/saml:Assertion/saml:AuthnStatement/saml:AuthnContext/saml:AuthnContextClassRef')->value
or return undef;
$classref =~ /SpidL(\d)$/ or return undef;
return $1;
});
has 'attributes' => (is => 'lazy', builder => sub {
return {
map { $_->getAttribute('Name') => $_->findnodes("*[local-name()='AttributeValue']")->[0]->string_value }
$_[0]->xpath->findnodes("/samlp:Response/saml:Assertion/saml:AttributeStatement/saml:Attribute"),
}
});
use Carp;
use Crypt::OpenSSL::RSA;
use DateTime;
use DateTime::Format::XSD;
use Mojo::XMLSig;
sub validate {
my ($self, %args) = @_;
$self->SUPER::validate(%args) or return 0;
my $xpath = $self->xpath;
# TODO: validate IssueInstant
croak "Missing 'in_response_to' argument for validate()"
if !defined $args{in_response_to};
croak sprintf "Invalid InResponseTo: '%s' (expected: '%s')",
$self->InResponseTo, $args{in_response_to}
if $self->InResponseTo ne $args{in_response_to};
croak sprintf "Invalid Destination: '%s'", $self->Destination
if !grep { $_ eq $self->Destination } @{$self->_spid->sp_assertionconsumerservice};
if ($self->success) {
# We expect to have an <Assertion> element
croak sprintf "Response/Issuer (%s) does not match Assertion/Issuer (%s)",
$self->Issuer, $self->Assertion_Issuer
if $self->Issuer ne $self->Assertion_Issuer;
croak sprintf "Invalid Audience: '%s' (expected: '%s')",
$self->Assertion_Audience, $self->_spid->sp_entityid
if $self->Assertion_Audience ne $self->_spid->sp_entityid;
croak sprintf "Invalid InResponseTo: '%s' (expected: '%s')",
$self->Assertion_InResponseTo, $args{in_response_to}
if $self->Assertion_InResponseTo ne $args{in_response_to};
# this validates all the signatures in the given XML, and requires that at least one exists
my $pubkey = Crypt::OpenSSL::RSA->new_public_key($self->_idp->cert->pubkey);
Mojo::XMLSig::verify($self->xml, $pubkey)
or croak "Signature verification failed";
# SPID regulations require that Assertion is signed, while Response can be not signed
croak "Response/Assertion is not signed"
if $xpath->findnodes('/samlp:Response/saml:Assertion/dsig:Signature')->size == 0;
my $now = DateTime->now;
# exact match is ok
croak sprintf "Invalid NotBefore: '%s' (now: '%s')",
$self->NotBefore->iso8601, $now->iso8601
if DateTime->compare($now, $self->NotBefore) < 0;
# exact match is *not* ok
croak sprintf "Invalid NotOnOrAfter: '%s' (now: '%s')",
$self->NotOnOrAfter->iso8601, $now->iso8601
if DateTime->compare($now, $self->NotOnOrAfter) > -1;
# exact match is *not* ok
croak sprintf "Invalid SubjectConfirmationData/NotOnOrAfter: '%s' (now: '%s')",
$self->SubjectConfirmationData_NotOnOrAfter->iso8601, $now->iso8601
if DateTime->compare($now, $self->SubjectConfirmationData_NotOnOrAfter) > -1;
croak "Invalid SubjectConfirmationData/\@Recipient'"
if !grep { $_ eq $self->Assertion_Recipient } @{$self->_spid->sp_assertionconsumerservice};
croak "Mismatch between Destination and SubjectConfirmationData/\@Recipient"
if $self->Destination ne $self->Assertion_Recipient;
} else {
# Authentication failed, so we expect no <Assertion> element.
}
return 1;
}
sub success {
my ($self) = @_;
return $self->StatusCode eq 'urn:oasis:names:tc:SAML:2.0:status:Success';
}
sub spid_session {
my ($self) = @_;
return undef if !$self->success;
return Net::SPID::Session->new(
idp_id => $self->Issuer,
nameid => $self->NameID,
session_index => $self->SessionIndex,
attributes => $self->attributes,
level => $self->spid_level,
assertion_xml => $self->xml,
);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
( run in 1.034 second using v1.01-cache-2.11-cpan-71847e10f99 )