⚠️ WORK IN PROGRESS (but should be useable)⚠️
PHP package for SPID authentication based on php-saml.
This PHP package is aimed at implementing SPID Service Providers. SPID is the Italian digital identity system, which enables citizens to access all public services with a single set of credentials. This package provides a layer of abstraction over the SAML protocol by exposing just the subset required in order to implement SPID authentication in a web application.
Features:
- routing-agnostic, can be integrated in any web framework / CMS
- sessionless (apart from a short-lived internal session used to store the request ID and IdP name until the IdP responds)
- does not currently support Attribute Authority (AA).
Alternatives for PHP:
- spid-php based on SimpleSAMLphp
- spid-php3, a lean implementation that does not rely on external SAML packages
Alternatives for other languages:
![]() Compliance with SPID regulations (for Service Providers) |
status (! = TODO) | comments |
---|---|---|
Metadata: | ||
parsing of IdP XML metadata (1.2.2.4) | ! | currently you can configure a single IdP supplying its metedata url in the idp_metadata_url key of config.yml ; the implementation of a workflow to configure the metadata for multiple IdPs is underway, see: #12; the implementation is not currently checking the AgID signature, see: #17 |
parsing of AA XML metadata (2.2.4) | Attribute Authority is unsupported | |
SP XML metadata generation (1.3.2) | ! | the SP metadata is made available at the /metadata.php endpoint; it is currently lacking the AttributeConsumingService (#18) and the optional Organization key (#19) |
AuthnRequest generation (1.2.2.1): | ||
generation of AuthnRequest XML | ! | the generated AuthnRequest is not 100% compliant, see: #2 |
HTTP-Redirect binding | ✓ | |
HTTP-POST binding | ||
AssertionConsumerServiceURL customization |
! | the underlying PHP package we are using as a basis for this SDK (onelogin/php-saml) allows customization of the AuthnRequest, but we are not exposing yet this interface; this is tracked in: #21 |
AssertionConsumerServiceIndex customization |
! | see: #21 |
AttributeConsumingServiceIndex customization |
! | see: #21 |
AuthnContextClassRef (SPID level) customization |
! | see: #21 |
RequestedAuthnContext/@Comparison customization |
||
RelayState customization (1.2.2) |
! | the RelayState parameter is currently sent in clear, see: #20 |
Response/Assertion parsing | ||
verification of Response/Signature value (if any) |
! | the underlying package can be configured to request a signed Response (security.wantMessagesSigned key) but we are not making use of it ATM, see: #23 |
verification of Response/Signature certificate (if any) against IdP/ |
✓ | the underlying package checks the signature using the certificate found in the IdP metadata, see: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L369 |
verification of Assertion/Signature value |
! | OK but strict mode must be set, see: #22 |
verification of Assertion/Signature certificate against IdP/ |
✓ | the underlying package checks the signature using the certificate found in the IdP metadata, see: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L369 |
verification of SubjectConfirmationData/@Recipient |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L302 but the spec requires it, see: #25 |
verification of SubjectConfirmationData/@NotOnOrAfter |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L308 but the spec requires it, see: #25 |
verification of SubjectConfirmationData/@InResponseTo |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L296 but the spec requires it, see: #25 |
verification of Issuer |
! | the underlying package checks that if there is any Issuer it is valid: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L265 but the spec requires it, see: #25 |
verification of Destination |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L227 but the spec requires it, see: #25 |
verification of Conditions/@NotBefore |
! | the underlying package checks it only of it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L909 but the spec requires it, see: #25 |
verification of Conditions/@NotOnOrAfter |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L915 but the spec requires it, see: #25 |
verification of Audience |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L252 but the spec requires it, see: #25 |
parsing of Response with no Assertion (authentication/query failure) |
✓ | the underlying package checks it: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L783 |
parsing of failure StatusCode (Requester/Responder) |
! | the underlying package checks it if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/Response.php#L456 but the spec requires it, see: #25 |
verification of RelayState (saml-bindings-2.0-os 3.5.3) |
✓ | this is currently checked in the user code: https://github.com/simevo/spid-php2/blob/master/www2/index.php#L78 |
Response/Assertion parsing for SSO (1.2.1, 1.2.2.2, 1.3.1): | ||
parsing of NameID |
✓ | the underlying package offers three functions to access the NameID : getNameId , getNameIdFormat and getNameIdNameQualifier , that can be used in the user code: https://github.com/simevo/spid-php2/blob/master/www2/index.php#L74 |
parsing of AuthnContextClassRef (SPID level) |
! | to be implemented, see: #24 |
parsing of attributes | ✓ | the underlying package offers the getAttributes function to access the attributes, that can be used in the user code: https://github.com/simevo/spid-php2/blob/master/www2/index.php#L73 |
Response/Assertion parsing for attribute query (2.2.2.2, 2.3.1): | ||
parsing of attributes | Attribute Authority is unsupported | |
LogoutRequest generation (for SP-initiated logout): | ||
generation of LogoutRequest XML | ✓ | |
HTTP-Redirect binding | ✓ | |
HTTP-POST binding | ||
LogoutResponse parsing (for SP-initiated logout): | ||
parsing of LogoutResponse XML | ✓ | |
verification of LogoutResponse/Signature value (if any) |
! | the underlying package can be configured to request a signed LogoutResponse (security.wantMessagesSigned key) but we are not making use of it ATM, see: #23 |
verification of LogoutResponse/Signature certificate (if any) against IdP metadata |
✓ | the underlying package checks the signature using the certificate found in the IdP metadata, see: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutResponse.php#L180 |
verification of Issuer |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutResponse.php#L152, whereas the spec requires it, see: #25 |
verification of Destination |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutResponse.php#L162, whereas the spec requires it, see: #25 |
PartialLogout detection | the underlying package does not support partial logout | |
LogoutRequest parsing (for third-party-initiated logout): | ||
parsing of LogoutRequest XML | ✓ | |
verification of LogoutRequest/Signature value (if any) |
! | the underlying package can be configured to request a signed LogoutRequest (security.wantMessagesSigned key) but we are not making use of it ATM, see: #23 |
verification of LogoutRequest/Signature certificate (if any) against IdP metadata |
✓ | the underlying package checks the signature using the certificate found in the IdP metadata, see: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutRequest.php#L385 |
verification of Issuer |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutRequest.php#L370, whereas the spec requires it, see: #25 |
verification of Destination |
! | the underlying package checks it only if it is present: https://github.com/onelogin/php-saml/blob/master/lib/Saml2/LogoutRequest.php#L358, whereas the spec requires it, see: #25 |
parsing of NameID |
✓ | the underlying package offers the getNameId function to access the NameID , that could be used in the user code |
LogoutResponse generation (for third-party-initiated logout): | ||
generation of LogoutResponse XML | ✓ | |
HTTP-Redirect binding | ✓ | |
HTTP-POST binding | ||
PartialLogout customization | the underlying package does not support partial logout | |
AttributeQuery generation (2.2.2.1): | ||
generation of AttributeQuery XML | Attribute Authority is unsupported | |
SOAP binding (client) | Attribute Authority is unsupported |
- bin/ auxiliary scripts
- example/ contains a demo application
- src/ contains the implementation
- test/ will contain the unit tests
Tested on amd64 Debian 9.5 (stretch, current stable) and 10 (buster, current unstable) with PHP 7.0-7.2.
sudo apt install composer make openssl php-curl php-zip php-xml
Before using this package, you must:
-
Install prerequisites with composer
-
Download and verify the Identity Provider (IdP) metadata files; it is advised to place them in a separate directory, for example example/idp_metadata/. A convenience tool is provided for this purpose: bin/download_idp_metadata.php.
-
Generate key and certificate for the Service Provider (SP) and patch the php-saml package to comply with the SPID standard.
All steps can be performed in an unattended fashion with:
composer install --no-dev
make
pushd example && ../bin/download_idp_metadata.php && popd
NOTE: during testing, it is highly adviced to use the test Identity Provider spid-testenv2.
All classes provided by this package reside in the Italia\Spid2
namespace.
Load them using the composer-generated autoloader:
require_once(__DIR__ . "/../vendor/autoload.php");
The main class is Italia\Spid2\Sp
(service provider), sample instantiation:
$settings = [
'spEntityId' => "https://sp.example.com",
'idpMetadataFolderPath' => $home . "/idp_metadata",
'idpList' => array(
'testenv2'
),
...
];
$sp = new Italia\Spid2\Sp($settings);
The service provider is now ready for use, as in:
// shortname of IdP, same as the name of corresponding IdP metadata file, without .xml
$idpName = 'testenv';
// return url
$returnTo = 'https://example.com/return_to_url';
// SPID level (1, 2 or 3)
$spidLevel = 1;
$sp->login($idpName, $returnTo, $spidLevel);
...
$attributes = $sp->getAttributes();
var_dump($attributes);
$sp->logout();
A basic demo application is provided in the example/ directory.
To use:
- in
example/settings.php
:
- adapt the base url (
$base
) to your needs (use am IP address or a FQDN that is visible to the IdP) - make sure the IdP metadata corresponding to the IdPs listed in the
idpList
key are present inexample/idp_metadata
-
in
example/login.php
change the IdP that will be used to login -
Serve the
example
dir from your preferred webserver -
visit https://sp.example.com/metadata.php to get the SP (Service Provider) metadata, then copy these over to the IdP and register the SP
-
visit: https://sp.example.com and click
login
.
This screencast shows what you should see if all goes well:
It is advised to install a browser plugin to trace SAML messages:
-
Firefox:
-
Chrome/Chromium:
In addition, you can use the SAML Developer Tools provided by onelogin to understand what is going on
Launch unit tests with PHPunit:
phpunit --stderr --testdox tests
This project complies with the PSR-2: Coding Style Guide.
Lint the code with:
./vendor/bin/phpcs --standard=PSR2 xxx.php
For your contributions please use the git-flow workflow.
- SPID page on Developers Italia
Lorenzo Cattaneo and Paolo Greppi.
Copyright (c) 2018, simevo s.r.l.
License: BSD 3-Clause, see LICENSE file.