Authen-NZRealMe

 view release on metacpan or  search on metacpan

lib/Authen/NZRealMe/ServiceProvider.pm  view on Meta::CPAN

        $xc,
        q{/soap12:Envelope/soap12:Body/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/saml:Assertion/saml:Subject/saml:NameID}
    ) or die "Unable to find FLT in iCMS response: $xml\n";
    return $flt->to_literal;
}

sub _https_post {
    my($self, $url, $headers, $body) = @_;

    my $curl = new WWW::Curl::Easy;

    $curl->setopt(CURLOPT_URL,        $url);
    $curl->setopt(CURLOPT_POST,       1);
    $curl->setopt(CURLOPT_HTTPHEADER, $headers);
    $curl->setopt(CURLOPT_POSTFIELDS, $body);
    $curl->setopt(CURLOPT_SSLCERT,    $self->ssl_cert_pathname);
    $curl->setopt(CURLOPT_SSLKEY,     $self->ssl_key_pathname);

    if ($self->{disable_ssl_verify}){
        $curl->setopt(CURLOPT_SSL_VERIFYPEER, 0);
    }
    else {
        $curl->setopt(CURLOPT_SSL_VERIFYPEER, 1);
        $curl->setopt(CURLOPT_CAPATH, $self->ca_cert_pathname);
    }

    my($resp_body, $resp_head);
    open (my $body_fh, ">", \$resp_body);
    $curl->setopt(CURLOPT_WRITEDATA, $body_fh);
    open (my $head_fh, ">", \$resp_head);
    $curl->setopt(CURLOPT_WRITEHEADER, $head_fh);

    my $resp;
    my $retcode = $curl->perform;
    if($retcode == 0) {
        $resp_head =~ s/\A(?:HTTP\/1\.1\s+200\s+Connection\s+established).*?\r?\n\r?\n//is; # Remove any '200' response from a proxy
        $resp_head =~ s/\A(?:HTTP\/1\.1 100 Continue)?[\r\n]*//; # Remove any '100' responses and/or leading newlines
        my($status, @head_lines) = split(/\r?\n/, $resp_head);
        my($protocol, $code, $message) = split /\s+/, $status, 3;
        my $headers = [ map { split /:\s+/, $_, 2 } @head_lines];
        $resp = HTTP::Response->new($code, $message, $headers, $resp_body);
    }
    else {
        $resp = HTTP::Response->new(
            500, 'Error', [], $curl->strerror($retcode)." ($retcode)\n"
        );
    }

    return $resp;
}


sub _verify_assertion {
    my($self, $xml, %args) = @_;

    my $request_id = $args{request_id}
        or die "Can't resolve to assertion without original request ID\n";

    my $binding = $args{saml_response} ? 'http_post' : 'http_artifact';

    my @ns_prefs = ($ns_soap11, $ns_saml, $ns_samlp, $ns_xenc);
    my $xc = $self->_xpath_context_dom($xml, @ns_prefs);

    my $encrypted = $binding eq 'http_post';
    if($xc->findnodes('//saml:EncryptedAssertion/xenc:EncryptedData')) {
        $encrypted = 1;
        $xml = $self->decrypt_assertion($xml);
        $xc = $self->_xpath_context_dom($xml, @ns_prefs);
    }

    # Check for SOAP error

    if($binding eq 'http_artifact') {
        if(my($error) = $xc->findnodes('//soap11:Fault')) {
            my $code   = $xc->findvalue('./faultcode',   $error) || 'Unknown';
            my $string = $xc->findvalue('./faultstring', $error) || 'Unknown';
            die "SOAP protocol error:\n  Fault Code: $code\n  Fault String: $string\n";
        }
    }


    # Extract the SAML result code

    my $response = $self->_build_resolution_response($xc, $xml, $binding);
    return $response if $response->is_error;


    # Make sure the response payload is signed

    my $idp  = $self->idp;
    my $verifier = $self->_verify_assertion_signature($idp, $xml);


    # Look for the SAML Response Subject payload in a signed section

    my $transport_prefix =  $binding eq 'http_post'
        ? '/samlp:Response'
        : '/soap11:Envelope/soap11:Body/samlp:ArtifactResponse/samlp:Response';

    my $encrypted_prefix = $encrypted
        ? '/saml:EncryptedAssertion'
        : '';

    my $subj_xpath = $transport_prefix . $encrypted_prefix
        . '/saml:Assertion/saml:Subject';
    my($subject) = $verifier->find_verified_element($xc, $subj_xpath);
    my $assertion = $subject->parentNode();


    # Confirm that subject is valid for our SP

    $self->_check_subject_confirmation($xc, $subject, $request_id);


    # Check that it was generated by the expected IdP

    my $idp_entity_id = $idp->entity_id;
    my $from_sp = $xc->findvalue('./saml:NameID/@NameQualifier', $subject) || '';
    die "SAML assertion created by '$from_sp', expected '$idp_entity_id'. Assertion follows:\n$xml\n"
        if $from_sp ne $idp_entity_id;


    # Check that it's intended for our SP

    if($self->type eq 'login') {  # Not provided by assertion IdP
        my $sp_entity_id  = $self->entity_id;
        my $for_sp = $xc->findvalue('./saml:NameID/@SPNameQualifier', $subject) || '';
        die "SAML assertion created for '$for_sp', expected '$sp_entity_id'\n$xml\n"



( run in 3.951 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )