Net-SPID

 view release on metacpan or  search on metacpan

example/idp_metadata/spid-testenv-identityserver.xml  view on Meta::CPAN

<?xml version="1.0" encoding="UTF-8"?> 
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_2487e8a5-3a05-488c-8fa6-fe32b8ae96c8" entityID="https://spid-testenv-identityserver:9443/samlsso">  
  <!-- Per test non viene richiesta la firma del metadata come avverrebbe in produzione --> 
  <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 
    <KeyDescriptor use="signing"> 
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
        <X509Data> 
          <!-- certificato di default dell'identity server, se modificato è necessario cambiarlo --> 
          <X509Certificate> 
            MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UE 
            CAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxv 
            Y2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQsw 
            CQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UE 
            AwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTou 
            sMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5 
            HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQID 

example/idp_metadata/spid-testenv2.xml  view on Meta::CPAN

<?xml version='1.0' encoding='UTF-8'?>
<ns0:EntityDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" entityID="http://localhost:8088"><ns0:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:t...
VDENMAsGA1UEBwwEUm9tYTAeFw0xODA2MjYxMDM5MzBaFw0xOTA2MjYxMDM5MzBa
MBwxCzAJBgNVBAYTAklUMQ0wCwYDVQQHDARSb21hMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAudciVxyXnPvTt2r8+3wE9DsibXu9fZwHjji0rOE7FJj8
fm/2rE0/GfDNyymGv7LHx9vKO8p1Ot4cl0ou/bR70PtJW9tM2ssyWPmHQXmBX84F
B/IuuOitABEtc3/HsWOyAA23XanCGpv6j6CW8TRjO+bi7nQnW3y/rLuCoTkBihH4
QGA0bkg8he56BSa3sAPnyO3VLavlYv3yYCQDqR+r2UM1f8gNPTlE5UIQzOYPXv1w
/YrrFhEx7xUYPh1J2e4J6xRRbZqzvB74QF0t0A0XueCITXLuVQ5eQ1rIWFAL1nwM
qWvep+3HvDpq0K8nzGFjnut6ElfyyhPp8+/H0zBOkQIDAQABMA0GCSqGSIb3DQEB
CwUAA4IBAQBw4mfH+WtR/etTVWK1Jy9DXWxAazFViQcVBualTuleRSHZjCv/nyv4
YbyFlTNarDI+LF+iG2rCABxgY40L6FpN9Gnsa5wijuKs0E6ZAvJ/rYfrYkE8wd0y

lib/Net/SPID/SAML.pm  view on Meta::CPAN

    # Validate request. This will throw an exception in case of failure.
    $r->validate;
    
    return $r;
}

sub metadata {
    my ($self) = @_;
    
    my $md   = 'urn:oasis:names:tc:SAML:2.0:metadata';
    my $dsig = 'http://www.w3.org/2000/09/xmldsig#';
    my $x = XML::Writer->new( 
        OUTPUT          => 'self', 
        NAMESPACES      => 1,
        PREFIX_MAP      => {
            $md   => 'md',
            $dsig => 'ds',
        },
    );
    
    my $ID = $self->sp_entityid;
    $ID =~ s/[^a-z0-9_-]/_/g;
    $x->startTag([$md, 'EntityDescriptor'],
        entityID => $self->sp_entityid,
        ID => $ID);
    
    $x->startTag([$md, 'SPSSODescriptor'],
        protocolSupportEnumeration => 'urn:oasis:names:tc:SAML:2.0:protocol',
        AuthnRequestsSigned => 'true',
        WantAssertionsSigned => 'true');
    
    {
        $x->startTag([$md, 'KeyDescriptor'], use => 'signing');
        $x->startTag([$dsig, 'KeyInfo']);
        $x->startTag([$dsig, 'X509Data']);
        
        my $cert = $self->sp_cert->as_string;
        $cert =~ s/^-+BEGIN CERTIFICATE-+\n//;
        $cert =~ s/\n-+END CERTIFICATE-+\n?//;
        $x->dataElement([$dsig, 'X509Certificate'], $cert);
        
        $x->endTag(); #ds:X509Data
        $x->endTag(); #ds:KeyInfo
        $x->endTag(); #KeyDescriptor
    }
    $x->dataElement([$md, 'NameIDFormat'],
        'urn:oasis:names:tc:SAML:2.0:nameid-format:transient');
    
    foreach my $acs_index (0..$#{$self->sp_assertionconsumerservice}) {
        $x->emptyTag([$md, 'SingleSignOnService'],

lib/Net/SPID/SAML/IdP.pm  view on Meta::CPAN

use Carp;
use Crypt::OpenSSL::X509;
use Mojo::XMLSig;
use XML::XPath;

sub new_from_xml {
    my ($class, %args) = @_;

    my $xpath = XML::XPath->new(xml => $args{xml});
    $xpath->set_namespace('md', 'urn:oasis:names:tc:SAML:2.0:metadata');
    $xpath->set_namespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
    
    if ($xpath->findnodes('/md:EntityDescriptor/dsig:Signature')->size > 0) {
        # TODO: validate certificate against a known CA
        Mojo::XMLSig::verify($args{xml})
            or croak "Signature verification failed";
    }
    
    $args{entityID} = $xpath->findvalue('/md:EntityDescriptor/@entityID')->value;
    
    $args{sso_urls} //= {};
    for my $sso ($xpath->findnodes('/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleSignOnService')){
        my $binding = $sso->getAttribute('Binding');

lib/Net/SPID/SAML/In/Base.pm  view on Meta::CPAN

    
    print STDERR $self->xml;
}

sub _build_xpath {
    my ($self) = @_;
    
    my $xpath = XML::XPath->new(xml => $self->xml);
    $xpath->set_namespace('saml',  'urn:oasis:names:tc:SAML:2.0:assertion');
    $xpath->set_namespace('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
    $xpath->set_namespace('dsig',  'http://www.w3.org/2000/09/xmldsig#');
    return $xpath;
}

sub validate {
    my ($self, %args) = @_;
    
    my $xpath = $self->xpath;
    
    # detect IdP
    my $idp = $self->_idp($self->_spid->get_idp($self->Issuer))
        or croak "Unknown Issuer: " . $self->Issuer;
    
    return 1;
}

sub _validate_post_or_redirect {
    my ($self) = @_;
    
    my $xpath = $self->xpath;
    
    if ($xpath->findnodes('/*/dsig:Signature')->size > 0) {
        # message is signed, it's HTTP-POST
        my $pubkey = Crypt::OpenSSL::RSA->new_public_key($self->_idp->cert->pubkey);
        Mojo::XMLSig::verify($self->xml, $pubkey)
            or croak "Signature verification failed";
    } elsif ($self->url) {
        # this is supposed to be a HTTP-Redirect binding
        my $u = URI->new($self->url);
        
        # verify the response
        my $SigAlg = $u->query_param('SigAlg');
        my $pubkey = Crypt::OpenSSL::RSA->new_public_key($self->_idp->cert->pubkey);
        if ($SigAlg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') {
            $pubkey->use_sha256_hash;
        } elsif ($SigAlg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384') {
            $pubkey->use_sha384_hash;
        } elsif ($SigAlg eq 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512') {
            $pubkey->use_sha512_hash;
        } else {
            croak "Unsupported SigAlg: $SigAlg";
        }
        
        my $sig = decode_base64($u->query_param_delete('Signature'));
        $pubkey->verify($u->query, $sig)
            or croak "Signature verification failed";
    
        return 1;

lib/Net/SPID/SAML/In/Response.pm  view on Meta::CPAN

            $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')",

lib/Net/SPID/SAML/Out/Base.pm  view on Meta::CPAN


sub _signature_template {
    my ($self, $ref) = @_;
    
    my $cert = $self->_spid->sp_cert->as_string;
    $cert =~ s/^-+BEGIN CERTIFICATE-+\n//;
    $cert =~ s/\n-+END CERTIFICATE-+\n?//;
    
    # TODO: replace this with XML::Writer calls in order to disable UNSAFE?
    return <<"EOF"
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
      <ds:Reference URI="#$ref">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <ds:DigestValue></ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue></ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>$cert</ds:X509Certificate>

lib/Net/SPID/SAML/Out/Base.pm  view on Meta::CPAN

    my $xml = $self->xml(binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect');
    print STDERR $xml, "\n";
    
    my $payload = '';
    rawdeflate \$xml => \$payload;
    $payload = encode_base64($payload, '');
    
    my $u = URI->new($url);
    $u->query_param($args{param}, $payload);
    $u->query_param('RelayState', $args{relaystate}) if defined $args{relaystate};
    $u->query_param('SigAlg', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
    
    my $sig = encode_base64($self->_spid->sp_key->sign($u->query), '');
    $u->query_param('Signature', $sig);

    return $u->as_string;
}

sub post_form {
    my ($self, $url, %args) = @_;
    



( run in 1.506 second using v1.01-cache-2.11-cpan-71847e10f99 )