Skip to content

Setup SimpleSAMLphp with the clave module to connect to NIA.CZ using eIDAS SAML

Michal Prochazka edited this page May 4, 2020 · 1 revision

It is assumed that SimpleSAMLphp is installed on https://example.org/simplesaml/, private key is in certs/server.pem and public key in certs/server.crt.

Install the clave module

cd /var/simplesamlphp/modules
git clone https://github.com/rediris-es/simplesamlphp-clave2.git clave
cd clave
composer install --no-dev

Add NIA as a remote IdP by creating metadata/clave-idp-remote.php (example for test environment)

<?php
$claveMeta['urn:microsoft:cgg2010:fpsts'] = [
    'entityID' => 'urn:microsoft:cgg2010:fpsts',
    'SingleSignOnService'  => 'https://tnia.eidentita.cz/FPSTS/saml2/basic',
    // Endpoint URL of the SLO service (if not set,
    // will logout at the bridge and return)
    'SingleLogoutService'  => 'https://tnia.eidentita.cz/FPSTS/saml2/basic',
    //Accept only signed SLO request
    'sign.logout' => true,
    //Sign all emmitted redirects
    'redirect.sign' => true,
    //Validate all received redirects
    'redirect.validate' => true,
    // has to be set
    'certData' => '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',
    'keys' => [
        [
            'encryption' => false,
            'signing' => true,
            'type' => 'X509Certificate',
            'X509Certificate' => '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',
        ],
    ],
];

Create an SP to face NIA in metadata/clave-sp-hosted.php

<?php
$claveMeta['eidasSP'] = [
    'entityid' => 'https://example.org/simplesaml/module.php/clave/sp/metadata.php/clave/eidasSP/eidasSP',
    'providerName' => 'My organization name',
    'providerName.forward' => false,
    'idpEntityID' => 'urn:microsoft:cgg2010:fpsts',
    'issuer' => 'https://example.org/simplesaml/module.php/clave/sp/metadata.php/clave/eidasSP/eidasSP',
    'useMetadataUrl' => true,
    'dialect' => 'eidas',
    'subdialect' => 'eidas',
    // [Optional] STORK minimum accepted level of quality on the
    // authentication (1: username+pwd <-> 4:smartcard). Automatically
    // converted to eIDAS LoA values (<=2,3,>=4)
    'QAA' => 1,
    'certificate' => 'server.crt',
    'privatekey'  => 'server.pem',
    'assertions.encrypted' => true,
    'assertions.encrypted.only' => false,
    'SPType'        => 'public',
    'NameIDFormat'  => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
    'LoA'  =>  'http://eidas.europa.eu/LoA/low',
    'showCountrySelector' => false,
    'countries' => ['CS' => 'Česko'],
];

You need to register the SP at NIA. Both issuer and metadata URL is https://example.org/simplesaml/module.php/clave/sp/metadata.php/clave/eidasSP/eidasSP, token endpoint is https://example.org/simplesaml/module.php/clave/sp/clave-acs.php/eidasSP. NIA loads the certificate (public key) from metadata URL.

Create an IdP for connected SAML SPs in metadata/saml20-idp-hosted.php

$metadata['__DYNAMIC:1__'] = [
    'host' => '__DEFAULT__',
    'privatekey' => 'server.pem',
    'certificate' => 'server.crt',
    'auth' => 'eidasSP',
    'saml20.sign.response' => true,
    'saml20.sign.assertion' => true,
    'redirect.sign' => true,
    'redirect.validate' => true,
    'assertion.encryption' => true,
];

Add remote SAML SPs to metadata/saml20-sp-remote.php

$metadata['https://example.com/simplesaml/module.php/saml/sp/metadata.php/default-sp'] = [
        'SingleLogoutService' => 'https://example.com/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',
        'AssertionConsumerService' => 'https://example.com/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
        'certData' => 'MIID...w==',
        'attributes' => [
                // eidas
                'PersonIdentifier', 'FirstName', 'FamilyName', 'DateOfBirth', 'CurrentAddress', 'PlaceOfBirth',
                // stork
                'eMail', 'countryCodeOfBirth', 'age', 'isAgeOver',
                // CZ
                'http://schemas.eidentity.cz/moris/2016/identity/claims/phonenumber',
                'http://schemas.eidentita.cz/moris/2016/identity/claims/tradresaid',
                'http://schemas.eidentita.cz/moris/2016/identity/claims/idtype',
                'http://schemas.eidentita.cz/moris/2016/identity/claims/idnumber',
        ],
];

Add eIDAS authentication source to config\authsources.php

'eidasSP' => [
    'clave:SP',
    'discoURL' => 'clave/sp/countryselector.php',
    'hostedSP' => 'eidasSP',
],

Remote SP connects regularly

<?php
require_once('../lib/_autoload.php');
$as = new \SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth();
$attributes = $as->getAttributes();

and gets something like

Array
(
    [CurrentFamilyName] => Array
        (
            [0] => DVOŘÁKOVÁ
        )
    [CurrentGivenName] => Array
        (
            [0] => PAVLA
        )
    [DateOfBirth] => Array
        (
            [0] => 1955-06-07
        )
    [PlaceOfBirth] => Array
        (
            [0] => Bílence
        )
    [CurrentAddress] => Array
        (
            [0] => <eidas:LocatorDesignator>131</eidas:LocatorDesignator>
<eidas:Thoroughfare></eidas:Thoroughfare>
<eidas:PostName>Arnoltice u Děčína</eidas:PostName>
<eidas:PostCode>40714</eidas:PostCode>
<eidas:CvaddressArea>Arnoltice</eidas:CvaddressArea>
        )
    [ZR10 IdNumber] => Array
        (
            [0] => 111111881
        )
    [ZR10 IdType] => Array
        (
            [0] => ID
        )
    [TRadresaID] => Array
        (
            [0] => <TRadresaID xmlns="http://schemas.eidentita.cz/moris/2016/identity/claims/tradresaid">
  <okresKod>3502</okresKod>
  <obecKod>562343</obecKod>
  <castObceKod>434</castObceKod>
  <uliceKod></uliceKod>
  <postaKod>40714</postaKod>
  <stavebniObjektKod>1813</stavebniObjektKod>
  <adresniMistoKod>1813</adresniMistoKod>
  <cisloDomovni>131</cisloDomovni>
  <cisloOrientacni></cisloOrientacni>
  <cisloOrientacniPismeno></cisloOrientacniPismeno>
</TRadresaID>
        )
    [PersonIdentifier] => Array
        (
            [0] => CZ/CZ/ecbc9c55-4679-48b4-9a1c-2395c0c44ebb
        )
)