AuthorisationChallenge zwraca kod 200 przy błędnym SessionToken

AuthorisationChallenge zwraca kod 200 przy błędnym SessionToken
W1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10
0

Mam funkcjonalność testowania wprowadzonego tokenu nadanego użytkownikowi na stronie ksef (dalej AuthToken) przed korzystaniem. Dla tego korzystam z endpintu "ksef-test.mf.gov.pl/api/online/Session/AuthorisationChallenge". Problem polega na tym, że jeśli wprowadzę błedny AuthToken, to endpoint nie zwraca żadnego błędu. A nawet jeśli zmienię NIP na inny, dowolny, też nie zwraca żadnych błędów. Problemy się zaczynają przy próbie pracować z tym AuthToken, już w momencie pobierania tokena sesyjnego "ksef-test.mf.gov.pl/api/online/Session/InitToken" zwraca "Call failed with status code 400 (Bad Request): ". Czy to jest nie poprawne zachowanie "AuthorisationChallenge"? Czy są inne sposoby przetestować AuthToken? Z tego co rozumiem, "ksef-test.mf.gov.pl/api/online/Session/InitToken" nie nadaje się do testowania, bo w tym momencie, już nadaję token sesyjny. Z góry dziękuję za odpowiedź.

P.S. Z prawidłowym AuthToken wszystko działa poprawnie.

var request = BaseApiUrl.AppendPathSegment(SessionUrlPath)
.AppendPathSegment("AuthorisationChallenge")
.WithHeader("Content-Type", "application/json")
.WithHeader("Accept", "application/json")
.WithHeader("SessionToken", AuthToken)
.WithTimeout(10);
var response = await request.PostJsonAsync(
new
{
contextIdentifier = new
{
type = "onip",
identifier = customerNIP
}
});

var request = BaseApiUrl.AppendPathSegment(SessionUrlPath).AppendPathSegment("InitToken")
.WithHeader("accept", "application/json")
.WithHeader("Content-Type", "application/octet-stream")
.WithHeader("SessionToken", AuthToken);

var response = await request.PostAsync(new ByteArrayContent(binaryData));

woolfik
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1617
0

Najpierw pobierasz /online/Session/AuthorisationChallenge aby uzyskać challenge i timestamp

Kopiuj
url = f"{base_url}/online/Session/AuthorisationChallenge"
    headers = {
        "Content-Type": "application/json",
    }
    data = {
        "contextIdentifier": {
            "type": "onip",
            "identifier": global_var.nip
        }
    }

to jest ta najprostsza rzecz

teraz wywołujesz
/online/Session/InitToken
przekazując tam 3 informacje włąsnie challenge, nip (musi być ten sam co potem w wysyłanej FV i tu nie ma znaczenia czy to testówka czy prod) oraz TOKEN

Kopiuj
<?xml version="1.0" encoding="utf-8"?>
<ns3:InitSessionTokenRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://ksef.mf.gov.pl/schema/gtw/svc/types/2021/10/01/0001" xmlns:ns3="http://ksef.mf.gov.pl/schema/gtw/svc/online/auth/request/2021/10/01/0001">
  <ns3:Context>
    <Challenge xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">{global_challenge}</Challenge>
    <Identifier xsi:type="ns2:SubjectIdentifierByCompanyType" xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">
      <ns2:Identifier>{global_var.nip}</ns2:Identifier>
    </Identifier>
    <DocumentType xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">
      <ns2:Service>KSeF</ns2:Service>
      <ns2:FormCode>
        <ns2:SystemCode>FA (2)</ns2:SystemCode>
        <ns2:SchemaVersion>1-0E</ns2:SchemaVersion>
        <ns2:TargetNamespace>http://crd.gov.pl/wzor/2023/06/29/12648/</ns2:TargetNamespace>
        <ns2:Value>FA</ns2:Value>
      </ns2:FormCode>
    </DocumentType>
    <Token xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">{global_token}</Token>
  </ns3:Context>
</ns3:InitSessionTokenRequest>

natomiast ten global_token jest ... złożóny po pierwsze wskazujesz tam timestamp z AuthorisationChallenge w postaci milisekund następnie dajesz pionową krechę | i podajesz AuthToken ze strony KSEF dla danego NIP następnie cały ten ciąg znaków musisz zakodować plikiem PEM (do pobrania ze stronty ksef) i na samym końcu jeszcze base64 taki gotowy xml wysyłasz i wtedy on Ci zwróci w odpowiedzi SessionToken, który już przekazujesz do:

headers = {
'accept': 'application/json',
'SessionToken': session_token,
'Content-Type': 'application/json'
}

przy wywołaniu /online/Invoice/Send

xoree
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poraj
  • Postów: 58
0
Kopiuj
<?php

// Funkcja do uzyskania challenge i timestamp z endpointu /online/Session/AuthorisationChallenge
function getChallengeAndTimestamp($apiUrl, $nip) {
    $curl = curl_init();

    $data = array(
        'contextIdentifier' => array(
            'type' => 'onip',
            'identifier' => $nip
        )
    );
    $postData = json_encode($data);

    curl_setopt_array($curl, [
        CURLOPT_URL => $apiUrl . "/online/Session/AuthorisationChallenge",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/json",
        ],
        CURLOPT_POSTFIELDS => $postData
    ]);

    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $curlError = curl_error($curl);
    curl_close($curl);

    if ($curlError) {
        echo "Błąd cURL: " . $curlError . "\n";
        return false;
    }

    if ($httpCode === 201) {
        return json_decode($response, true);
    } else {
        echo "Kod odpowiedzi HTTP: " . $httpCode . "\n";
        echo "Odpowiedź serwera: " . $response . "\n";
        return false;
    }
}

// Funkcja do szyfrowania tokenu kluczem publicznym
function encryptToken($token, $publicKey) {
    $encryptedToken = '';
    if (openssl_public_encrypt($token, $encryptedToken, $publicKey)) {
        return base64_encode($encryptedToken);  // Zwróć zaszyfrowany token zakodowany w Base64
    } else {
        echo "Nie udało się zaszyfrować tokenu.\n";
        return false;
    }
}

// Funkcja do uzyskania tokenu sesji KSeF
function getKSeFSessionToken($apiUrl, $encryptedToken, $challenge, $nip) {
    $xmlRequest = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<ns3:InitSessionTokenRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:ns2="http://ksef.mf.gov.pl/schema/gtw/svc/types/2021/10/01/0001" 
    xmlns:ns3="http://ksef.mf.gov.pl/schema/gtw/svc/online/auth/request/2021/10/01/0001">
  <ns3:Context>
    <Challenge xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">{$challenge}</Challenge>
    <Identifier xsi:type="ns2:SubjectIdentifierByCompanyType" xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">
      <ns2:Identifier>{$nip}</ns2:Identifier>
    </Identifier>
    <DocumentType xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">
      <ns2:Service>KSeF</ns2:Service>
      <ns2:FormCode>
        <ns2:SystemCode>FA (2)</ns2:SystemCode>
        <ns2:SchemaVersion>1-0E</ns2:SchemaVersion>
        <ns2:TargetNamespace>http://crd.gov.pl/wzor/2023/06/29/12648/</ns2:TargetNamespace>
        <ns2:Value>FA</ns2:Value>
      </ns2:FormCode>
    </DocumentType>
    <Token xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/types/2021/10/01/0001">{$encryptedToken}</Token>
  </ns3:Context>
</ns3:InitSessionTokenRequest>
XML;

    echo "Wygenerowany XML przed wysyłką:\n" . $xmlRequest . "\n";

    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $apiUrl . "/online/Session/InitToken",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/xml; charset=utf-8",  // Nagłówek dla XML
            "Accept: application/xml",  // Oczekujemy odpowiedzi w formacie XML
        ],
        CURLOPT_POSTFIELDS => $xmlRequest
    ]);

    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $curlError = curl_error($curl);
    curl_close($curl);

    if ($curlError) {
        echo "Błąd cURL: " . $curlError . "\n";
    }

    echo "Kod odpowiedzi HTTP: " . $httpCode . "\n";
    echo "Odpowiedź serwera (jako tekst):\n" . $response . "\n";  // Wyświetlenie pełnej odpowiedzi serwera

    // Jeśli odpowiedź jest w XML, spróbuj ją sparsować jako XML
    if ($httpCode === 200) {
        $data = simplexml_load_string($response);

        if ($data === false) {
            echo "Błąd podczas parsowania odpowiedzi XML:\n";
            foreach (libxml_get_errors() as $error) {
                echo $error->message . "\n";
            }
            return false;
        }

        return $data;
    }

    return false;
}

// Funkcja do wysyłania faktury z użyciem SessionToken
function sendInvoice($apiUrl, $sessionToken, $invoiceFile) {
    $curl = curl_init();

    $headers = [
        'accept: application/json',
        'SessionToken: ' . $sessionToken,
        'Content-Type: application/xml'
    ];

    // Wczytaj zawartość pliku XML
    $invoiceData = file_get_contents($invoiceFile);

    curl_setopt_array($curl, [
        CURLOPT_URL => $apiUrl . "/online/Invoice/Send",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POSTFIELDS => $invoiceData  // Wysyłamy zawartość pliku XML
    ]);

    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $curlError = curl_error($curl);
    curl_close($curl);

    if ($curlError) {
        echo "Błąd cURL: " . $curlError . "\n";
    }

    echo "Kod odpowiedzi HTTP: " . $httpCode . "\n";
    echo "Odpowiedź serwera:\n" . $response . "\n";

    return $httpCode === 200 ? json_decode($response, true) : false;
}

// Cały proces

$apiUrl = "https://ksef-demo.mf.gov.pl/api";
$nip = "xxx";  // Twój NIP
$apiKey = "xxx";  // Twój klucz API
$invoiceFile = __DIR__ . '/faktura_213-10-2024_2024-10-24.xml';  // Ścieżka do pliku XML z fakturą

// Krok 1: Pobierz challenge i timestamp
$challengeData = getChallengeAndTimestamp($apiUrl, $nip);
if ($challengeData) {
    $challenge = $challengeData['challenge'];
    $timestamp = $challengeData['timestamp'];

    // Krok 2: Przygotowanie tokenu do zaszyfrowania
    $tokenData = $timestamp . '|' . $apiKey;  // Łączenie timestamp i tokenu

    // Krok 3: Szyfrowanie tokenu kluczem publicznym
    $publicKeyPath = __DIR__ . '/publicKey.pem';  // Ścieżka do pliku klucza publicznego

    if (file_exists($publicKeyPath) && is_readable($publicKeyPath)) {
        $publicKey = file_get_contents($publicKeyPath);
        $encryptedToken = encryptToken($tokenData, $publicKey);

        if ($encryptedToken) {
            // Krok 4: Uzyskaj token sesji
            $sessionToken = getKSeFSessionToken($apiUrl, $encryptedToken, $challenge, $nip);

            if ($sessionToken) {
                echo "Uzyskano token sesji.\n";

                // Krok 5: Wczytaj i wyślij fakturę z pliku XML
                $sendResult = sendInvoice($apiUrl, $sessionToken, $invoiceFile);

                if ($sendResult) {
                    echo "Faktura została wysłana.\n";
                } else {
                    echo "Nie udało się wysłać faktury.\n";
                }
            } else {
                echo "Nie udało się uzyskać tokenu sesji.\n";
            }
        }
    } else {
        echo "Nie udało się odczytać pliku z kluczem publicznym.\n";
    }
}
?>

Dostaje :Kod odpowiedzi HTTP: 201 Odpowiedź serwera: {"timestamp":"2024-10-26T04:36:46.490Z","challenge":"20241026-CR-ABE36025B7-CA3D584718-8F"} (i to jest ok)
A następnie : Wygenerowany XML przed wysyłką: 20241026-CR-1C86ECE11B-790E65E4AE-DD 5771876968 KSeF FA (2) 1-0E http://crd.gov.pl/wzor/2023/06/29/12648/ FA mqYthJM2GqsNhGvXWcTxuEkZr0fz8BNo6SuhthgHB9YkN8UyyPtS/sNVIyYRYGEgqu62mQMBIOYXTelSkyILGupK1Up5GZQc3utPLKCVxz4QaJpVPR3gTKtO91ChnlbXxLzfKWsjQF/UrJbEXe9EmrqJ7nt6CsGT48KHcf/iltRgkDMiXy8HozCdmPSdpiy2sbShtNTuvYfyXHdpSROoscgcJzX5VkV3amTwCZ9XR53nVXtt3DR6T46GbMBSTA15eyYVxySKy+XbbM/+wA+K7YBqTJtieSMVyJ61SGk0ZWuiWU6hMjQ8gDYI6rvlb4TjNkl0SYCkDMCdptnQ+tD+WA== Kod odpowiedzi HTTP: 415 Odpowiedź serwera (jako tekst): Nie udało się uzyskać tokenu sesji.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.