Unable to validate Signature

Implementace(2) - Vytvoření požadavku (AuthnRequest)

Z kroku 1 jsme získali ověřenou URL adresu pro přesměrování uživatele na autorizaci

Nyní je třeba vytvořit autorizační požadavek a tento předat NIA IdP

Postup

  1. Vytvoření XML požadavku na autorizaci
  2. Podepsání požadavku
  3. Získání finální podoby požadavku
  4. Přesměrování uživatele

Vytvoření a podepsání XML požadavku na autorizaci

    
    private function generateAuthnRequest(EntityDescriptor $idp_descriptor)
    {
        // stejně jako v předchozích ukázkách, NiaContainer a NiaServiceProvider jsou
        // implementace specifické pro vaši aplikaci / produkční prostředí
        // jejich popis je mimo možnosti tohoto manuálu
        $nia_container = new NiaContainer($this);
        $service_provider = new NiaServiceProvider();
        ContainerSingleton::setContainer($nia_container);

        // získání url adresy, na kterou přesměrovat uživatele při metodě HTTP-REDIRECT
        $urls = $this->extractSSOLoginUrls($idp_descriptor);
        $sso_redirect_login_url = $urls[Constants::BINDING_HTTP_REDIRECT];

        // samotný AuthnRequest
        $auth_request = new AuthnRequest();
        // unikátní ID
        $auth_request->setId($nia_container->generateId());
        // Issuer, neboli "Unikátní URL adresa zabezpečené části Vašeho webu"
        $auth_request->setIssuer($nia_container->getIssuer());
        // explicitní deklarace příjemce zprávy
        $auth_request->setDestination($sso_redirect_login_url);
        // adresa kam se má uživatel přesměrovat při dokončení procesu na straně IdP
        $auth_request->setAssertionConsumerServiceURL(NiaServiceProvider::$AssertionConsumerServiceURL);
        // vyžadovaná úroveň ověření identity
        // LOW dovoluje využít NIA jméno+heslo+sms, stejně jako datovou schránku FO nebo identitu zahraničního občana
        // SUBSTANTIAL pak dovoluje méně variant
        // HIGH dovoluje pouze elektronický občanský průkaz
        $auth_request->setRequestedAuthnContext([
            'AuthnContextClassRef' => [NiaServiceProvider::LOA_LOW],
            'Comparison' => 'minimum'
        ]);

        // vygenerování nepodepsaného požadavku
        $auth_request_xml_domelement = $auth_request->toUnsignedXML();
        // přidání vyžadovaných atributů (informací o uživateli), element samlp:Extensions
        $exts = new NiaExtensions($auth_request_xml_domelement);
        $exts->addAllDefaultAttributes();
        $auth_request_xml_domelement = $exts->toXML();

        $auth_request_xml = $auth_request_xml_domelement->ownerDocument->saveXML($auth_request_xml_domelement);
        $auth_request_xml_domelement = DOMDocumentFactory::fromString($auth_request_xml);

        // vložení vlastního podpisu naším privátním klíčem
        $auth_request_xml_domelement = $service_provider->insertSignature($auth_request_xml_domelement->documentElement);

        return $auth_request_xml_domelement;
    }
    

AuthnRequest - obsah požadavku

Důležité náležitosti AuthnRequest
  • samlp:Issuer - obsahuje identifikátor SeP dle konfigurace v administraci NIA
  • samlp:AuthnRequest atribut AssertionConsumerServiceURL - obsahuje URL kam se přesměruje uživatel po dokončení procesu u IdP
  • samlp:RequestedAuthnContext - obsahuje požadovanou úroveň jistoty identifikace uživatele
  • eidas:RequestedAttributes - obsahuje seznam požadovaných informací o identitě, a zda jsou tyto vyžadovány (atribut isRequired) či nikoliv
  • Požadavek musí být podepsán privátním klíčem, který odpovídá certifikátu v SeP metadatech (příp. v konfiguraci SeP v administraci NIA)
    
<?xml version="1.0"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_5a595399-999a-4a39-9088-7f62a27edabc" Version="2.0" IssueInstant="2024-04-18T21:51:55Z" Destination="https://tnia.identitaobcana.cz/FPSTS/saml2/basic" AssertionConsumerServiceURL="https://nia.otevrenamesta.cz/ExternalLogin">
  <saml:Issuer>https://nia.otevrenamesta.cz/</saml:Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
  <ds:Reference URI="#_5a595399-999a-4a39-9088-7f62a27edabc"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>hXVgcrpj8UCcJDH9GD8qbw5mIt5S8g7FIEcs+J7E+h0=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>HwpHbLbHe0cMgJ4WtlXTrFecdLcCOJr4uMrJwr3s8ATtRr/ryZuIp7sDwMjcN09Vbu6zMm+vCL46xQQXYqMsfT9iQzWEK5vUCqjDtvr2Zp65nv1i2cNnUg+8eDlS5bgYPYBJXzs/eevE1Qoz+ZaieNNcmBaVmBSpQOjnaPr05MNUCmg/esYlQg4RLv8Oxtd4i0+C7RErVI1KweoGBEYvt9R0E2/qMcxwfQAveiwBLBSI7aKme7+mHCr1Fiq/KMeXhTmh3sqTZpxPtyT30CNE8FbThthK+zrHxu3LcD0xD1Tvc2/7FQbaX+EgZLDO/4t1n7BerolQbsIMh0RaZqwiCg==</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDdDCCAlygAwIBAgIRAP9sUbldL412M4EpX2fV5PwwDQYJKoZIhvcNAQELBQAwJDEiMCAGA1UEAwwZaHR0cHM6Ly9vdGV2cmVuYW1lc3RhLmN6LzAeFw0xOTEwMDEwOTM1MjhaFw0yMjA5MTUwOTM1MjhaMBQxEjAQBgNVBAMMCXN6cmMtdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7C+gGDVHuZSYz2MDq21UB/e3UXiU7L3iJvv8GEzJoi+SvauCU/Ui5oGc/w2MqZ21E463aDadjksRFSB+9z/uw2yNna+Wctg2RoY4CMZNdp/MxunRIT9/U0ecXVHPcqsnTnVykK1QYUv8BaGHLQH0Okk/7+SWHR/MMXcJ7OTI4owm8bFRKN/PFaUtCSNYxhUnP51quWwx6EXoHXZWAq//7YCZP+WL7dcmnql4JxjpZGq4lINqCGA8WXw0EuXbUs5vakl5SFmDMezmiO5IEi1Mk5vmv649p2gUa4qpVPgHkhCqOSRB0BAeEh63hZM05Z+HkDb6R8VYAdFW3ZEL0lXw8CAwEAAaOBsDCBrTAJBgNVHRMEAjAAMB0GA1UdDgQWBBRJIq+FqevCnV5u7guRRfs8k4KbmDBfBgNVHSMEWDBWgBTypM00nD30BAjXOIrO8l6xFnzxvaEopCYwJDEiMCAGA1UEAwwZaHR0cHM6Ly9vdGV2cmVuYW1lc3RhLmN6L4IUdCc7pFsR+OGBk+abd7ssRaIIM1EwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQBHSwJPSnC6G+978X/Lk4UMx1QMXmUpvaWnELBMyAcdpRsN9RsOsiJKLYiTAHFLHDwAF0cd/2ZxcwqHu2dX2jwVfOE+Z3UhHEBmvLTPBQq96y62KO4Px7//6gQchK+zER5ZfOP7jAqqziIu+SuI4xJ3zBgEGb4wr3EdQqonNnk6rZh7uJlnCWaoZACg5+S97aK77HaJgk775lFYhDiuQBRD6GKLJoqR1Yvg12RN0X1UbCV5hUF0UEOgHhbNNmZIU9qrKeVKefekDSjzd8xDIU6Ic5w3gKS01CecLQL7/tSpi/s3X+1f4yTjozurqNjUV7gBxcyYRw+4vE4aa4qx/gWd</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
  <saml:Conditions>
    <saml:AudienceRestriction>
      <saml:Audience>https://nia.otevrenamesta.cz/ExternalLogin</saml:Audience>
    </saml:AudienceRestriction>
  </saml:Conditions>
  <samlp:RequestedAuthnContext Comparison="minimum">
    <saml:AuthnContextClassRef>http://eidas.europa.eu/LoA/low</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
  <samlp:Extensions xmlns:eidas="http://eidas.europa.eu/saml-extensions">
    <eidas:SPType xmlns:eidas="http://eidas.europa.eu/saml-extensions">public</eidas:SPType>
    <eidas:RequestedAttributes xmlns:eidas="http://eidas.europa.eu/saml-extensions">
      <eidas:RequestedAttribute Name="http://www.stork.gov.eu/1.0/age" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://www.stork.gov.eu/1.0/countryCodeOfBirth" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://eidas.europa.eu/attributes/naturalperson/CurrentAddress" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://eidas.europa.eu/attributes/naturalperson/DateOfBirth" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://www.stork.gov.eu/1.0/eMail" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://www.stork.gov.eu/1.0/isAgeOver" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <eidas:AttributeValue>18</eidas:AttributeValue>
      </eidas:RequestedAttribute>
      <eidas:RequestedAttribute Name="http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://schemas.identitaobcana.cz/moris/2016/identity/claims/idnumber" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://schemas.identitaobcana.cz/moris/2016/identity/claims/idtype" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://schemas.identitaobcana.cz/moris/2016/identity/claims/tradresaid" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
      <eidas:RequestedAttribute Name="http://schemas.eidentity.cz/moris/2016/identity/claims/phonenumber" isRequired="false" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
    </eidas:RequestedAttributes>
  </samlp:Extensions>
</samlp:AuthnRequest>
    

Získání finální podoby požadavku

Adresa na kterou přesměrujeme uživatele se skládá následovně

  • IdP SSO HTTP-REDIRECT binding URL adresa (viz. IdP Metadata, element SingleSignOnService)
  • GET parametr SAMLRequest
  • AuthnRequest požadavek, s validním obsahem, podepsaný, zkomprimovaný (gzdeflate), enkódovaný (base64) a url-enkódovaný (urlencode)

    // EntityDescriptor pro IdP
    $idp_descriptor = generateIdpDescriptor();
    // viz. výše
    $authn_request = generateAuthnRequest($idp_descriptor);
    // komprese a enkódování požadavku
    $xml = $signed_request->ownerDocument->saveXML();

    $query = gzdeflate($xml);
    $query = base64_encode($query);
    $query = urlencode($query);

    // získání URL adresy
    // $redirect_url je popsána v posledním bodě kroku 1
    $final_url = $redirect_url . (parse_url($redirect_url, PHP_URL_QUERY) ? '&' : '?') . 'SAMLRequest=' . $query;

Obsah finální URL (vygenerováno právě teď):

"https://tnia.identitaobcana.cz/FPSTS/saml2/basic?SAMLRequest=1Vhpc%2BK4Fv3evyJFf6QSL9gYqCRT3gCDDdjGbF9eCVvYAu%2FyAvz6J0hCp9PLzLyZqXldRZXxle7R0dXV1ZEffztG4V0Fc4yS%2BKnBPNCN354%2FPWIQhWlPLIsgtmBWQlzckX4x7l0bnhplHvcSgBHuxSCCuFe4PVs09B77QPfSPCkSNwkb71x%2B7gEwhnlBCDTuNOWp8R8e8F2%2B1e3ed7tdcM%2BBFvlHdzr3wq7NAlaAHti6jbvFG2kCQRwxLqEW4wLEBTHRLHdPc%2FdMZ84yPZ78%2BE3jTiHzQDEorl5BUaS4R1FFjMAD8mBcoAIkWxfE4ME9U%2F2ZPbepC3eW2hLeZEDxjaacxLiMYG7DvEIudCz9C9wFLSlglcPrPIsrmHosYB6DUE98FDeer%2BHtXRnnzz91fKTed330cM9GPplBmcPX6Hr4ZWyCUNf1Q916SHKfYmmapuguRfp4GPmfG8%2Bf7u7e3KGnxbvkiiaDOImRC0J0vobFgEWQeHdi6Cc5KoLoB9gMxdAX7Ht4dO9dhos%2FN6jLCF%2FGuFL8w2g098b0Pkpy%2BDnH4B4HgOXbL7gXVAvuIImNC%2B8cS3tqfP5jWXKd5TwHMd4leYS%2Ffv1dZl%2FFEMYVDJMUevf4bYKE3Z8D%2FG7gHqlvOSrIJznwJwNIovP5FrYvKAsQlvA5WC18N0%2F3HUd2R8qwO1A62bbmI63g7Y4v9DXVxc2RoDYD%2BunK6L3z1XBbgZfXD6l0W%2FUXj2GdDrf6dghp1%2FBH3LIIV%2FO8D11Pd%2BXpKOdKIx%2FVeQt3xHlh5VR%2B2pRaKmClNvbuhO4utmX7bETNSta59tE0V%2BvMwLt5F5nnpTrmK0fO9kpR5ewmbfNxxSDWncSO3%2BxAJbT5rb%2BeraXR6owpCCuVMZNzcwMQnEzcSAKLSLJTc7qPwSyneWPiyJFPQbwOTZ%2Bz9KozPRYeh%2BimLFhqvtCYcQ2TgaSuq6Jr0SpLZYZ7rHemWEFUS7pkawIYR1BoRkM5Z%2Fooo8YGXAXzKGjhbL5Jj7PiNG%2FR8kTt9LfzoAjGzXM%2BPJYt3VXoo8LMK5elhL65Baum6m90ZUpxBRMLEsyT0NxizQhoC2yyGsn%2B09Mt9O9i%2FekS%2FzE83dZixdNdBRTg9iJfCteObPQCPhuapniKLIvhyRdrTRJ9zRJnXexsQ0%2FnGNbg1HTF7hb8rK4Vcz0aJxstqNyJaKq6ZIr1SFGRIYsDkXFUsa43YGjR7tBo66du5Q0WrBstyvWSCd2WFejRpK2fRdiv6eN0rtaGotbTucEY%2BwAQ28nYi7wxd242QzKP6l40JX%2BykETDkFeTthsZBcE9Xznb2kdOEuGk%2BL46Ey%2FtZiKT%2F5KoC3LTHyiLYbmx12fWUDKWcSQKtpwVcgS9hUZV1Rmo51GCmnYFStmhHMQnA5eqWSPbsIzKtVtAAd7%2BgK2%2BLTW7Z6qs2dMkBs2lW%2Fislaw52dhMvJQyjmVsafMu5dDQXS2GMzfD8TxenA5jxlw7VUcCg6FuDunp4UAJTXs5tCjDWLkjYTrXuKSOOtu%2BNZ5Qsz5wCtmerI%2BBE894JiuX9bGtrpLharMUM4oS1vJm1lzqgudGcRZyo%2BM%2B3QwyLtQmmTwQO8tVTavlautgvgKHkLf7kWLAc4SmvKYixjjwVVS1uW7K%2Bg7gsnQx84eHQM6mtiXRkgjVoN0KNgbNb5rDg7JtW53FWvT6y9ZG1elwVXdksVZFEUwlrMhSPhdHl3UaWoYq7kXRkOhLTniKby4lyRppWbOfwUqOF3wp%2BKVl7XDnwI23kSLtrn62oS4VaelL81Nq0HSstAiJ%2FWqq5dNO2D724%2FOxAmqSyus%2Fn3Oc5niyK6R9bDWnA%2BnQBFtPwNgCmmYwaq3Wa2Vh0aFEwGR%2FrY3rNckjZ0j2Qy2%2FtM0k0VREH4qGSA9kOxvY2ralkHyTa0cUObJvTGlo16OZHcvtQbMrdFaUfuAc48iYxipy0gosY7JjjJPoeqmFJ10LTzEajfU1movDvj5UarFPux7Fbo5unQ1L1lux%2B3qxm6rNTcsJhqoUVfp8JplZt31qs%2BMpNzsKFNX2TfdSQ1SL3%2BymM2EvZtkZaWXTLjXuOGqdJV8dbDlSXFXPzJJ4Eh%2Fa%2BSYQylEYy0uQbETZ55t2l1QtQRiCkX8QBD7srwMFlaZkKe3BWB8lmcWsK59hrQm9YpytvOADp0876tQfBtvJJNpoTjfLx3AxJqfCQbH3Z69zVDSnrbl83fLHNs3I0NVNXaAKO0UUbq2azI47zffJucyzyd5ZCL50dE9rq25ylcoBkpFHyl961wr3sWjdjC9ljXpf8L6qiK%2Fiikg0D10UDX41iKWHLmeXRc60HLmXpg8tP1diX0m4V1l28%2Fzw%2FtUY1Hf5pL1XXQ29q8om7QU8FndyEqUgR%2FiiUCMUo6iMGjeeX%2FrJIdHM5Dx%2BftUDEHkAP8AyT1JAHpSeiFSY1Dde3%2FF8afsBjzeSl1nHF5WNX%2BXmdaCbDPk47MWJSJs3H8L82qNnz8gWh%2F8bRFpuQ%2BQ%2BUu%2BR3nC%2FcC9IwLdlAf8az2%2Fx7iYkBb6SXbhI8sODn1QXIHJfooAPG3cIX3xRDr2nxg6EmJgunn0i6EDxO7cfMtbFer%2B7du6VObrIt7%2FAyE3KuMhPcuLB6U5CeRH8ewQ%2Fhh7cVoq6blgQpuQel8SUXOZkwxWi5%2BUQ41%2BHcB9EKDxdIH4dzgNUwfgXoUwK%2Fr%2Bfxd%2FdZtAAKPw%2F44QwkSzTCuZ%2FO683Wjc2L3cPpvNWmj80vJm%2FncbfniKz60O7fsPZoX9g7n94TbAbwIiQ%2FvZ7UkRu8Jhc1pk29dp4otwQoAiT97iMtr8g7YIcxb8Y6SIHl%2FMFIO%2FfJw7fyP0O5zRIYvjPpcgP9ym%2BacQvMvBmev9t%2BPnTfwE%3D"

Další krok

Otevřením finální URL se spustí proces autorizace u NIA, jeho dokončením se vrátíte na tento tutoriál na Krok 3