PIV-I Identity Provider
This guide describes how to implement a NIEF SAML Identity Provider (IDP) system that authenticates Personal Identification Verification Interoperable (PIV-I) cardholders using the Federal Bridge PKI Certificate Authority (CA).
Background
PIV-I is a standard for smart cards issued by various non-federal organizations, typically operating at the state and local government level. The PIV-I standard is designed to be aligned/interoperable with the federal standard for PIV. There is tremendous information sharing value in being able to offer a turnkey SAML IDP capability to organizations that play a stakeholder role in the PIV-I cardholder community. This PIV-I IDP Implementation Guide provides detailed technical instructions that these PIV-I stakeholders can use to build such a capability and deploy it within NIEF.
This guide is designed around the use of free and open source software, primarily focusing on the use of the following:
Getting Started
This guide assumes the user is comfortable deploying a Linux (or equivalent) server with Apache HTTP Server, Java, and Apache Tomcat. No specific Shibboleth experience is required to follow this guide; however, if you are not comfortable deploying the prerequisites (Linux, Apache, Java, and Tomcat), then you should either acquire that experience or reach out to help@nief.org for assistance before you attempt to follow this guide. We have tested this guide with CentOS 7 Linux, but any modern Linux distribution that includes packages for the Apache HTTP Server should work. It is likely also possible to deploy within a Windows environment or other server environment, as long as you are able to adapt the HTTP configuration steps accordingly and as long as Java 8 is available for running Apache Tomcat and Shibboleth.
Enabling Authentication
The following section describes how to enable client certificate authentication (CCA) within the Apache HTTP Server. The server will need a valid server certificate in addition to all of this configuration, but the server certificate does not need to be issued by the same chain. In fact, it usually should NOT be from the same certificate chain, as the server certificate should come from a well-known CA (e.g., Let's Encrypt), and the client certificates should come from an organizational CA.
Certificate Authority Specification
Apache requires the full certificate chain, including an anchor (self-signed certificate), to be specified in the HTTP Server configuration. This is an important thing to understand, as typically with PIV-I (and with PIV) you are working with cross certified CAs, and if you only include cross certified certs in the CA certificate chain, Apache will fail with errors about chain length being too long (it gets stuck in a loop going through the chain back and forth).
Here is a copy of a sample valid chain (uni-directional chain) from the Foundation for Trusted Identity (FTI) Test CA to the Federal Test PKI CA: File:Fti-test-ca-chain.txt.
Within the Apache configuration, typically within the file ssl.conf you specify this CA file like this:
SSLCACertificateFile /etc/httpd/trust/fti-test-ca-chain.pem
For a production deployment, the CA chain would be different and would need to be constructed by following the chain and combining the certificates into a single PEM file.
Certificate Status / Revocation Checking
If Online Certificate Status Protocol (OCSP) is available for verifying that a certificate is current, then it is the simplest option to enable it with a single Apache HTTP Server directive:
SSLOCSPEnable On
In some cases (for example, in the current test CA chain), OCSP is not fully implemented, and it is necessary to instead use CRL (Certificate Revocation List) checking. This is enabled within the the Apache HTTP Server configuration:
SSLCARevocationFile /etc/httpd/trust/fti-crl.pem
This file must be updated regularly, as it only works if it is current, and by design the file has an expiration date to ensure software checking against the CRL is using a current copy of the CRL. The following script may be useful in configuring this in an automated fashion:
#!/bin/bash cd /etc/httpd/trust if [ -f FTITestCA.crl ]; then rm FTITestCA.crl; fi wget --quiet http://pki.fti.org/fti_ca/crl/FTITestCA.crl openssl crl -in FTITestCA.crl -inform DER -out fti-crl.pem systemctl restart httpd
A script such as this can then be configured in a crontab to ensure the CRL is up to date.
Configuring Client Certificate Authentication (CCA)
It is very rare that you will want to require CCA for the entire server. Typically, CCA is constrained to specific URL paths. At the top level of the HTTP Server SSL configuration, you should include this directive:
SSLVerifyClient none
Possibly in another configuration file (or in another section of the SSL configuration file) you would enable TLS CCA like this:
<Location "/pivi-test"> SSLOptions +StdEnvVars +ExportCertData SSLVerifyClient require SSLVerifyDepth 4 </Location>
A useful way to verify all Apache HTTP Server configuration is correct is to put a simple test page at the location used for testing. As long as this test page is only viewable after engaging in PIV-I authentication, you know that the server is configured correctly.
To enable CCA for use by the Shibboleth IDP, you will need a section like the following (the path could be different if the IDP was installed to a non-standard URL):
<Location "/idp/Authn/X509"> SSLOptions +StdEnvVars +ExportCertData SSLVerifyClient require SSLVerifyDepth 4 </Location>
Installing Shibboleth
Prior to installing Shibboleth, Java must be available. For most Linux distrubtions java-1.8.0-openjdk is a viable package; java-11-openjdk likely viable as well.
Downloading Shibboleth
The latest version of the Shibboleth IDP is available for download here: https://shibboleth.net/downloads/identity-provider/latest/.
The Shibboleth Wiki is a critical resource for understanding components and how to operate a Shibboleth IDP. While some configuration and installation details are specified in this guide, many other subtle details may be overlooked, and the content of the Shibboleth Wiki is almost always fresher and more useful than this guide.
Running the Shibboleth Installer
After you have downloaded and extracted the installer, run it as seen below. You may need to define JAVA_HOME based on the installed Java package. The values that should populate each question should all be largely self explanatory.
[shibboleth-identity-provider-3.4.3]# bin/install.sh Error: JAVA_HOME is not defined correctly. We cannot execute java shibboleth-identity-provider-3.4.3]# export JAVA_HOME=/etc/alternatives/jre_1.8.0/ [shibboleth-identity-provider-3.4.3]# bin/install.sh Source (Distribution) Directory (press <enter> to accept default): [/home/krug/src/idp-install/shibboleth-identity-provider-3.4.3] Installation Directory: [/opt/shibboleth-idp] Hostname: [new.nief.org] piv.nief.org SAML EntityID: https://piv.nief.org/idp/shibboleth Attribute Scope: [nief.org] nief.org Backchannel PKCS12 Password: Re-enter password: Cookie Encryption Key Password: Re-enter password: Warning: /opt/shibboleth-idp/bin does not exist. Warning: /opt/shibboleth-idp/edit-webapp does not exist. Warning: /opt/shibboleth-idp/dist does not exist. Warning: /opt/shibboleth-idp/doc does not exist. Warning: /opt/shibboleth-idp/system does not exist. Generating Signing Key, CN = piv.nief.org URI = https://piv.nief.org/idp/shibboleth ... ...done Creating Encryption Key, CN = piv.nief.org URI = https://piv.nief.org/idp/shibboleth ... ...done Creating Backchannel keystore, CN = piv.nief.org URI = https://piv.nief.org/idp/shibboleth ... ...done Creating cookie encryption key files... ...done Rebuilding /opt/shibboleth-idp/war/idp.war ... ...done BUILD SUCCESSFUL Total time: 2 minutes 18 seconds
All further configuration is handled by editing the installed configuration files in the chosen installation directory's conf directory.
Configuring Shibboleth Authentication
To enable X.509 CCA, you must specify it in the conf/idp.properties file (it defaults to using the Password login flow):
# Regular expression matching login flows to enable, e.g. IPAddress|Password idp.authn.flows=X509
Then you must configure the mechanism for determining the user identity based on the certificate. There is significant flexibility in how the certificate is parsed, and that is configured in conf/c14n/x500-subject-c14n-config.xml. Within this file you can parse out certificate fields by OID and/or by Subject Alt Name Types. The recommended mechanism for production is TBD, but in a test environment, the best option is to use the email subject alt name type. Enable this by removing the XML comments around the value:
<!-- First priority is given to any subjectAltNames specified (emailAddress is 1) --> <util:list id="shibboleth.c14n.x500.SubjectAltNameTypes"> <!-- <value>1</value> --> </util:list>
Configuring Shibboleth Trust with Partner Systems
There are many ways to enable trusted partners, and you can read about this in detail on the Shibboleth Wiki. But for our purposes, we are simply documenting how to quickly enable trust of the NIEF Testbed or NIEF Production environment. This configuration is done within the conf/metadata-providers.xml file. You need to enable the Metadata Provider that looks like this (by removing the comments):
<!-- <MetadataProvider id="HTTPMetadata" xsi:type="FileBackedHTTPMetadataProvider" backingFile="%{idp.home}/metadata/localCopyFromXYZHTTP.xml" metadataURL="http://WHATEVER"> <MetadataFilter xsi:type="SignatureValidation" certificateFile="%{idp.home}/credentials/metaroot.pem" /> <MetadataFilter xsi:type="RequiredValidUntil" maxValidityInterval="P30D"/> <MetadataFilter xsi:type="EntityRoleWhiteList"> <RetainedRole>md:SPSSODescriptor</RetainedRole> </MetadataFilter> </MetadataProvider> -->
The metadataURL is http://ref.gfipm.net/gfipm-signed-ref-metadata.xml for the NIEF Testbed and https://nief.org/trust-fabric/nief-trust-fabric.xml for NIEF in production. The signing certificates for each are http://ref.gfipm.net/ref-gfipm-ca.crt and https://nief.org/trust-fabric/nief-ca.crt respectively. You also need to either increase the max validity interval for NIEF to 45 days or simply remove it in the case of the NIEF Testbed which typically allows trust fabric to last for a year or more. The following is a fully configured example for the NIEF Testbed with inline certificate:
<MetadataProvider id="nief-testbed" xsi:type="FileBackedHTTPMetadataProvider" backingFile="%{idp.home}/metadata/gfipm-ref-cache.xml" metadataURL="https://ref.gfipm.net/gfipm-signed-ref-metadata.xml"> <MetadataFilter xsi:type="SignatureValidation" requireSignedRoot="true"> <PublicKey> MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0j7Etpn++n6z/NPs5752 gdisHr9GwjFouKC12GIxK6bOwgMdNLvTfMp+34fwRGeKTkwM65zmNob6WXxDMZJE KoaGg2UBYwaYsW/lc1ZPJpyEACTSgIxIJB4HNJuJYUm7uO5jebUevLVt091IE/6H OpxuRQNKE753JJQprxTT5O/Kb8wXBTHNWMNtdpSgC38uv9Yt+vAnDYOkrZanr2de jRFjxf3ZzkD4vihGCucEcjzt51IicDI/T/kjPLj9qvlb0z0NUxS/rikSahB0G6Qr xw6DSutxq7vovfU3o3dFs2e6GQ19uB4ZjTF/6uXYD+BdKlaUgjwihZBb+mPv43sc r9JWW2aShWs7ua9WihYfSCkbfj9zDPss25sCFdrVxpGYxdyYsF3FP2aWZJ9PaiaW y6lFZ+Gkk5OT4DWT2vhFQBymSxHs4Id5tz/3jGepFwZf+Q7IhaluHaFWooOw4cHa dfhx4oaMDrHe8N7OnVVrHJ5ChaGyYBA1Nk0xJZeBhF8HK9sNYdeYTYiqGYg6xkuu a82lDtbqwMmt2FMHQn2glZorxpcKiJf9G6ucwbN7gdAAEeRkoUnF/rf0DZWyb5NF GDJFqbx8mOtlFujT05NGq8l3oC5M3VKcnvlcuI6Ie9McentSGW+X0TrRbnoDn+lA VJvBhHNjfJcC6UuwECkRvmUCAwEAAQ== </PublicKey> </MetadataFilter> <MetadataFilter xsi:type="EntityRoleWhiteList"> <RetainedRole>md:SPSSODescriptor</RetainedRole> </MetadataFilter> </MetadataProvider>
Here is a sample provider for NIEF production:
<MetadataProvider id="nief-main" xsi:type="FileBackedHTTPMetadataProvider" backingFile="%{idp.home}/metadata/nief-cache.xml" metadataURL="https://nief.org/trust-fabric/nief-trust-fabric.xml"> <MetadataFilter xsi:type="SignatureValidation" requireSignedRoot="true"> <PublicKey> MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1fJixy7bY8R6nMXzNVrI Zu8bfOeu2vSasiNCQafvOcZSYj1n3wYuvS/kuIUFQ8tQyOWJjTsuUE7wEIkUmo6C sFh8tO9z0uJFBlicg//mlKRVCrRkXrwR7ScQMli4uVxFCHp6pEFqYLPx0nbENL36 kAOebTZpBhs2qPFk/KuVFrGx9VqZ//UiwjICL8aBAuxbi+Orvwe5OfttaSnn6bym Kl95i47wz6m1MfwzYJiWEritSmAodcDbGT49jG64+SItmT4O1YGRx7EtxwvYd9Ug 94LfOrsd3TgbMW6jpAfXxVuR9DX210haba2l47F14MeB3/VKbGGUqXThvP21Zfsd gQmfYPqmcNFQLLX59z+5iVujn6isZ0IUXl7VUVJFo259tph4f2FZeQaAxrYxynoF ENCvaDVEXI7XHQjhK0LV096DOK9F4FO3zwoPxa3EWc1ilAdzG4dQpMq7wQkn+K0v 6VL0rwSzz12aLS4/TIrPDcs8zTUz8QDbo1qcdCx2ABk2S0e01cQXCqaeqB8PZOmb gIK35Bdoh7g+4M9/V2agl9ohb+HDNktowESbJn2yrG3rizcuhR++t/IZ36PG0LVv 3yL4/UikxcLNkQSQktou6D27OFVdGT7XGZtByuFZCg78PtbChZGZfTUJYZOq7E+A EQSq3FyoF7lJ6RYXNqEl7F0CAwEAAQ== </PublicKey> </MetadataFilter> <MetadataFilter xsi:type="RequiredValidUntil" maxValidityInterval="P45D"/> <MetadataFilter xsi:type="EntityRoleWhiteList"> <RetainedRole>md:SPSSODescriptor</RetainedRole> </MetadataFilter> </MetadataProvider>
Running Shibboleth
The Shibboleth IDP can likely run in any supported servlet container. For simplicity's sake, these instructions assume the use of Apache Tomcat 8. The simplest and quickest way to enable the IDP within Tomcat is to create a file named idp.xml in the [TOMCAT_HOME]/conf/Catalina/localhost directory. The contents of this file specify the war file like this (the path specified in docBase will likely need to be updated to the installation path of Shibboleth):
<Context docBase="/opt/idp/war/idp.war" privileged="true" antiResourceLocking="false" swallowOutput="true" />
Since it is more common to install Tomcat directly rather than via a package manager, it may be useful to have a Linux startup script. One can be downloaded here: File:Tomcat.sh.
Proxying Shibboleth
Assuming Apache httpd was used from the earlier section as the web server, you will need to configure it to proxy the application server that runs the IDP. This is typically done with a small snippet of proxy configuration within Apache configuration files:
<Location /idp> ProxyPass ajp://localhost:8009/idp </Location>
Configuring NIEF Attributes
Shibboleth supports a rich XML configured and API driven capability for attribute resolution. Attributes can be filtered by relying party, by user, or conditionally based on various logic. The attribute values can be sourced from nearly anywhere, as long as code can be written to interact with the source (e.g., databases, web services, directories, programmatic derivation, etc.)
Attribute Filtering
Within the configuration file conf/attribute-filter.xml you can specify attribute release policies. The simplest such policy is to release all configured attributes to all trusted partners. A slightly more sophisticated example, that filters based on test user accounts and assumes a specific test attribute set, is available for download here: File:Attribute-filter.xml.
Attribute Resolution
Within the configuration file conf/attribute-resolver.xml you specify attributes and how to resolve their values. This is one of the most complex and flexible configuration points for Shibboleth, and detailed documentation is available on the Shibboleth Wiki. The flexibility is nearly endless, given the ability to write scripts and custom data connectors. Two samples are available here:
- This sample is an extremely simple sample that sends the UserName and a couple of statically defined attributes: File:Minimum-resolver.xml.
- This complicated sample configuration file sources attributes from a SQL database, statically for the organization, and from the filesystem in user files is available for download here: File:Attribute-resolver.xml.
Data Connectors
Shibboleth supports the development of new data connectors using their integration APIs. GTRI has developed many such data connectors over the years, and they are available for download on github:
- Texas DPS Data Connectors - This project consists of three data connectors developed for Texas DPS and supports querying two different web services, one external and one internal, as well as a copy of the GTRI local file system data connector, useful for testing.
- GTRI Test Data Connector - This is a simple test data connector, but also offers a convenient reference for implementing additional web services, as it is a simple sample of the API.
- BAE Data Connector - This data connector functions as a Backend Attribute Exchange (BAE) client. It is rather outdated and has really only ever been tested with the retired BAE service from IIR. NOT recommended for use.
- Shibboleth HTTP Dataconnector - This is a capability of Shibboleth to use a combination of Javascript and templates to call webservices to retrieve attributes. The link will lead to a sample GTRI created for using the IIR 28 CFR service.
Testing
It is always a good idea to test and validate a new IDP deployment within a test environment. The NIEF Testbed is intended for exactly this purpose.