1

We are converting a system we inherited: two web servers running IIS and Shibboleth, behind a load balancing server running HAPROXY. SSL certs are installed on each web server, and HAPROXY is configured as passthrough.

We want to replace the HAPROXY server with one running nginx, and we want to move the SSL cert off of the web servers to the edge, i.e. the nginx server.

So we want to go from this:

Before

to this:

enter image description here

And we are almost there. There is one snag: Shibboleth.

We built a new server, installed and configured nginx. We use the HOSTS file to point back and forth for testing. Once we are done, we'll repoint using DNS.

Step one, we configured nginx as a passthrough for SSL:

enter image description here

This worked perfectly.

But when we moved the cert to the nginx server, Shibboleth complains:
Unable to locate satisfiable bearer SubjectConfirmation in assertion

When trying to access content not protected by Shibboleth (https://example.com/open), it works fine - so the cert is set up correctly.

If we point HOSTS to HAPROXY, authenticate, then point HOSTS to nginx, it works (confirmed by browser tests while tailing nginx's access.log) In other words once the SAML cookie is set all is good. So it seems the problem happens when the IdP tries to send the assertions to .../Shibboleth.sso/SAML2/POST (Fiddler confirms)

I've turned on DEBUG logging on Shibboleth, and maybe I'll find something there but not yet.

Here is the nginx.conf:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
  include             mime.types;
  default_type        application/octet-stream;
  sendfile            on;
  keepalive_timeout   65;

  upstream farm {
    server 192.168.1.42:80; # WEB1
    server 192.168.1.43:80; # WEB2
  }

  server {
    listen              80;
    listen              443 default ssl;
    server_name         example.com;

    ssl_certificate         example.com.crt;
    ssl_certificate_key     example.com.key;
    ssl_trusted_certificate example.com.pem;

    location / {
      proxy_pass              http://farm;
      proxy_next_upstream     error timeout invalid_header http_500 http_502 http_503 http_504;
      proxy_set_header        Host            $host;
      proxy_set_header        X-Real-IP       $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }

}

And here's shibboleth2.xml

<SPConfig xmlns="urn:mace:shibboleth:2.0:native:sp:config"
    xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"    
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    clockSkew="180">

    <InProcess logger="native.logger">
        <ISAPI normalizeRequest="true" safeHeaderNames="true">
            <Site id="3" name="example.com"/>
        </ISAPI>
    </InProcess>

    <TCPListener address="192.168.1.42" port="1600" acl="192.168.1.42 192.168.1.43"/> 

    <RequestMapper type="Native">
        <RequestMap>
            <Host name="example.com">
              <Path name="closed" authType="shibboleth" requireSession="true">
              <Path name="open" authType="shibboleth" requireSession="false"/>
            </Host>
        </RequestMap>
    </RequestMapper>

    <ApplicationDefaults entityID="--spEntityId--"
                         REMOTE_USER="eppn persistent-id targeted-id uid"
                         cipherSuites="ECDHE+AESGCM:ECDHE:!aNULL:!eNULL:!LOW:!EXPORT:!RC4:!SHA:!SSLv2"
                         homeURL="https://example.com/closed">

        <Sessions lifetime="28800" timeout="86400" relayState="ss:mem" checkAddress="false" handlerSSL="false" cookieProps="https">
            <SSO entityID="--IdpEntityId--">SAML2 SAML1</SSO>

            <Logout>SAML2 Local</Logout>
            <Handler type="MetadataGenerator" Location="/Metadata" signing="false"/>
            <Handler type="Status" Location="/Status" acl="127.0.0.1 ::1"/>
            <Handler type="Session" Location="/Session" showAttributeValues="true"/>
            <Handler type="DiscoveryFeed" Location="/DiscoFeed"/>
        </Sessions>

        <Errors supportContact="root@localhost"
            helpLocation="/about.html"
            styleSheet="/shibboleth-sp/main.css"
            redirectErrors="/errors/shiberror.html" />

        <MetadataProvider type="XML" path="idp_metadata.xml" />

        <AttributeExtractor type="XML" validate="true" reloadChanges="false" path="attribute-map.xml"/>
        <CredentialResolver type="File" key="file.key" certificate="file.crt"/>
    </ApplicationDefaults>

    <SecurityPolicyProvider type="XML" validate="true" path="security-policy.xml"/>
    <ProtocolProvider type="XML" validate="true" reloadChanges="false" path="protocols.xml"/>
</SPConfig>

I'm stumped. Can you help?

biscuit314
  • 113
  • 9

2 Answers2

1

The problem was solved by modifying shibboleth2.xml, changing this:

<InProcess logger="native.logger">
    <ISAPI normalizeRequest="true" safeHeaderNames="true">
        <Site id="3" name="example.com"/>
    </ISAPI>
</InProcess>

to this:

<InProcess logger="native.logger">
    <ISAPI normalizeRequest="true" safeHeaderNames="true">
        <Site id="3" name="example.com" scheme="https" port="443"/>
    </ISAPI>
</InProcess>

That is adding scheme and port attributes to InProcess\ISAPI\Site

My understanding from Scott Cantor in the shibboleth mailing list is this is due to IIS not being able to virtualize servers. This feature was added to shibboleth as a workaround.

biscuit314
  • 113
  • 9
0

See this page;

https://support.aaf.edu.au/support/solutions/articles/19000031196-unable-to-locate-satisfiable-bearer-subjectconfirmation-in-assertion

Essentially the IdP is sending an entityID with an https:// prefix (note the 's'), but because the IIS web servers have been configured (either directly or indirectly) with an entityID with an http:// prefix (note the lack of 's').

The link above refers to a solution when the SP is used on an Apache server (change the ServerName directive to start "https://..."). In your case with IIS I don't know what the equivalent would be within IIS itself, but you could try changing the entityID="" entry in shibboleth2.xml to start https://

A workaround would be to use SSL for traffic between the nginx proxy and the web servers, configuring the IIS bindings for HTTPS again.

Steve365
  • 1,263
  • 9
  • 16