zeph Posted November 14, 2022 at 04:25 PM Report #628158 Posted November 14, 2022 at 04:25 PM Em 14/11/2022 às 16:16, samuquinha disse: Estou a fazer testes e o que até há alguns pedidos a trás na chamada do endpoint "https://preprod.autenticacao.gov.pt/oauthresourceserver/api/AttributeManager" me devolvia: algo contendo o accessToken, refresToken e oauthToken passou a devolver: "value":"{\"error\":\"Requested signature account already exists\",\"error_description\":\"Account already exists for citizen signatureAccountKeyAlias: BIxxxxxxxxyyyyyyyyyzzzzzzzz\"}" Qual o motivo para tal? Neste momento já está a devolver accessToken, refresToken e oauthToken. Pretendo agora invocar o endpoint "https://preprod.autenticacao.gov.pt/credentials/info", no entanto não sei quais os tokens a usar, nomeadamente no header "SAFEAuthorization" e "Authorization", bem como no parametro "processId". Alguém já passou por esta fase? Abraço Vocês não lêem a documentação ? (Apesar de ser muito má) 😛 A "chave" que permite identificar uma conta safe é formada por: • Identificador único do cidadão • NIPC da empresa; • Informação adicional (campo opcional utilizado para o cidadão fazer distinção entre contas associadas à mesma empresa). Se estás a receber esse erro , é porque já tens uma conta safe criada, no entanto estás a pedir a criação de outra com o mesmo Identificador único (dentificador único do cidadão+NIPC+Informação adicional). Em relação a tudo o que são endpoints do SAFE (authorize/signhash/crendentials,etc), tens de passar o SAFEAuthorization que é o accessToken que está no parametro "value" que apresentaste aí em cima (no teu caso, vêm com o erro da conta, mas os acessos vêm aí). O Authorization é uma Basic authentication, logo tens de enviar o "User:Password" em base64. No caso de testes, será "clientTest:Test" em base64. O processID é uma GUID. Tens essas informações discutidas já neste tópico 😄
samuquinha Posted November 14, 2022 at 04:54 PM Report #628160 Posted November 14, 2022 at 04:54 PM Em 14/11/2022 às 16:25, zeph disse: Vocês não lêem a documentação ? (Apesar de ser muito má) 😛 A "chave" que permite identificar uma conta safe é formada por: • Identificador único do cidadão • NIPC da empresa; • Informação adicional (campo opcional utilizado para o cidadão fazer distinção entre contas associadas à mesma empresa). Se estás a receber esse erro , é porque já tens uma conta safe criada, no entanto estás a pedir a criação de outra com o mesmo Identificador único (dentificador único do cidadão+NIPC+Informação adicional). Em relação a tudo o que são endpoints do SAFE (authorize/signhash/crendentials,etc), tens de passar o SAFEAuthorization que é o accessToken que está no parametro "value" que apresentaste aí em cima (no teu caso, vêm com o erro da conta, mas os acessos vêm aí). O Authorization é uma Basic authentication, logo tens de enviar o "User:Password" em base64. No caso de testes, será "clientTest:Test" em base64. O processID é uma GUID. Tens essas informações discutidas já neste tópico 😄 Obrigado pelos esclarecimentos. Já há tanta matéria neste forum e a documentação é como diz... Ao invocar esse endpoint dá-me erro: "The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable." Se tentar aceder ao endpoint de produção já me pede as credenciais... Para confirmar se o meu encoder está a calcular bem a concatenação de "clientTest:Test", o resultado é "Y2xpZW50VGVzdDpUZXN0" (tudo sem aspas)?
zeph Posted November 14, 2022 at 05:01 PM Report #628161 Posted November 14, 2022 at 05:01 PM On 11/14/2022 at 4:54 PM, samuquinha said: Para confirmar se o meu encoder está a calcular bem a concatenação de "clientTest:Test", o resultado é "Y2xpZW50VGVzdDpUZXN0" (tudo sem aspas)? Sim
bioshock Posted November 15, 2022 at 02:26 AM Report #628162 Posted November 15, 2022 at 02:26 AM Acontece-vos com regularidade o valor do endpoint interop createSignature vir vazio? É que sem isto, não apanho o Access Token / Refresh token. Umas vezes funciona, vem preenchido correctamente, mas 99% das vezes vem vazio. { "name": "http://interop.gov.pt/SAFE/createSignatureAccount?enterpriseNipc={nif}$enterpriseAdditionalInfo={info}$email=$signaturesLimit=450000$creationClientName=clientTest", "value": "", "state": "Available" } Depois da AMA redireccionar para o software, faço o seguinte: POST https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager Envio access_token Obtenho o token & authenticationContextId Espero 30s GET https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager?token={token}&authenticationContextId={authenticationContextId} Obtenho a informação de todos os interop's, excepto do createSignature
zeph Posted November 15, 2022 at 09:26 AM Report #628163 Posted November 15, 2022 at 09:26 AM (edited) On 11/15/2022 at 2:26 AM, bioshock said: Acontece-vos com regularidade o valor do endpoint interop createSignature vir vazio? É que sem isto, não apanho o Access Token / Refresh token. Umas vezes funciona, vem preenchido correctamente, mas 99% das vezes vem vazio. { "name": "http://interop.gov.pt/SAFE/createSignatureAccount?enterpriseNipc={nif}$enterpriseAdditionalInfo={info}$email=$signaturesLimit=450000$creationClientName=clientTest", "value": "", "state": "Available" } Depois da AMA redireccionar para o software, faço o seguinte: POST https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager Envio access_token Obtenho o token & authenticationContextId Espero 30s GET https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager?token={token}&authenticationContextId={authenticationContextId} Obtenho a informação de todos os interop's, excepto do createSignature Tive também alguns problemas com isso e não só aí. O que faço é: 1 - POST https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager Espera 15 segundos 2 - GET https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager Enquanto/Se a resposta do GET for vazia e não ultrapasse 15 tentativas { 3 - POST https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager 4 - GET https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager Espera 5 segundos } Se não cumprisse com o ponto 3, por vezes não tinha valor no atributo da conta,. Experimenta fazer isso. Caso obtenhas as credenciais logo a seguir, aconselho a esperares 5 segundos antes de pedires e ires pedindo de 5 em 5 segundos durante x tentativas (no meu caso pus 15) caso não tenha resultado. Eles lançam este processo de credenciais de forma assíncrona e retorna-te http status 401 enquanto não apresentar resultados. Na documentação, nada é muito claro. Tive de fazer várias tentativas em erro para chegar a um resultado coerente. Edited November 15, 2022 at 09:59 AM by zeph
samuquinha Posted November 15, 2022 at 10:45 AM Report #628165 Posted November 15, 2022 at 10:45 AM (edited) No endpoint "https://pprsafe.autenticacao.gov.pt/credentials/info" Com os parâmetros {"credentialID": "09a0c3a0-182b-4a1c-9c03-716b3c921b2d", "certificates": "chain", "clientData": {"processId": "5eca9b09-14bc-4879-870c-1a79367755e8", "clientName": "clientTest"}} Obtenho o erro {"error":"Bad Request","error_description":"Bad Request"} Se utilizer o GUID como obtenho da libraria que uso (em maísculas) {"credentialID": "09a0c3a0-182b-4a1c-9c03-716b3c921b2d", "certificates": "chain", "clientData": {"processId": "A1555C49-BAFC-46F6-83B0-F9F23F108827", "clientName": "clientTest"}} Obtenho o erro {"error":"Bad Request","error_description":"Invalid parameter processId"} Fico confuso o uuid tem que ser sempre minusculas Edited November 15, 2022 at 12:10 PM by samuquinha Com alguma insistência, passou a funcionar
Nel Posted November 15, 2022 at 12:13 PM Report #628168 Posted November 15, 2022 at 12:13 PM Em 11/11/2022 às 21:02, bioshock disse: Sim consegui, já tenho isto a adicionar a assinatura & o documento adicionado. Estou a utilizar um serviço pago, não estou a utilizar TCPDF. Em breve vou partilhar aqui o código. Dá-me alguns dias, falta-me resolver a situação do Access Token, enviar o código para a SAFE/AMA e assim que for autorizado, coloco aqui. 👍 Estou só com dificuldades em obter o Access Token dinamicamente, mas acho que já sei porquê. Consegues criar o PDF com a assinatura OK? Fica com o warning de "identity Unknown"? O meu esta a ficar com erro mesmo. Estou a adaptar o tcpdf. Qual o package que usas?
Usiruess Posted November 15, 2022 at 01:00 PM Report #628170 Posted November 15, 2022 at 01:00 PM No meu caso demorou 6 dias a ficar ativo
samuquinha Posted November 15, 2022 at 02:57 PM Report #628171 Posted November 15, 2022 at 02:57 PM Bem, já tenho tudo pronto para pedir autorização para assinar documentos, no entanto a resposta chega-me vazia (sem sad)... so sad pedido endpoint "https://pprsafe.autenticacao.gov.pt/v2/credentials/authorize": {"numSignatures": 1, "hashes": ["blablabla"], "clientData": { "processId": "c8976890-8772-4e4d-93d3-fe7d399afb29", "documentNames": ["documen_Name1"], "clientName": "clientTest" }, "credentialID": "aaa39a23-xxxx-yyyy-2354-aaaa13d3bbbb" } resposta: '' Alguém com mesmo problema?
Nel Posted November 15, 2022 at 03:24 PM Report #628172 Posted November 15, 2022 at 03:24 PM Em 15/11/2022 às 14:57, samuquinha disse: Bem, já tenho tudo pronto para pedir autorização para assinar documentos, no entanto a resposta chega-me vazia (sem sad)... so sad pedido endpoint "https://pprsafe.autenticacao.gov.pt/v2/credentials/authorize": {"numSignatures": 1, "hashes": ["blablabla"], "clientData": { "processId": "c8976890-8772-4e4d-93d3-fe7d399afb29", "documentNames": ["documen_Name1"], "clientName": "clientTest" }, "credentialID": "aaa39a23-xxxx-yyyy-2354-aaaa13d3bbbb" } resposta: '' Alguém com mesmo problema? Sim, tb não devolve nada. Por isso estou a usar o endpoint mais antigo: https://pprsafe.autenticacao.gov.pt/credentials/authorize
samuquinha Posted November 15, 2022 at 04:03 PM Report #628177 Posted November 15, 2022 at 04:03 PM Em 15/11/2022 às 15:24, Nel disse: Sim, tb não devolve nada. Por isso estou a usar o endpoint mais antigo: https://pprsafe.autenticacao.gov.pt/credentials/authorize Obrigado, Usando esse endpoint obtenho o erro: 'Internal Server Error -> Unexpected error while processing client request'
Nel Posted November 15, 2022 at 04:10 PM Report #628178 Posted November 15, 2022 at 04:10 PM Em 15/11/2022 às 16:03, samuquinha disse: Obrigado, Usando esse endpoint obtenho o erro: 'Internal Server Error -> Unexpected error while processing client request' Estas a colocar o teu credentialID?
samuquinha Posted November 15, 2022 at 04:44 PM Report #628180 Posted November 15, 2022 at 04:44 PM (edited) Em 15/11/2022 às 16:10, Nel disse: Estas a colocar o teu credentialID? Sim, estou a enviar os parametros necessários Se alterar o parametro hashes do pedido para uma cena trivial (conforme exemplo do SAFE - Signature Service) {"numSignatures": 1, "hashes": ["MDEwDQYJYIZIAWUDBAIBBQAEIAOxESPLqLyNN4XvBW718h4QGtEyMKfQmLNcl6CFRKUB"], "clientData": { "processId": "c8976890-8772-4e4d-93d3-fe7d399afb29", "documentNames": ["documen_Name1"], "clientName": "clientTest" }, "credentialID": "xxxxxxpppppp" } já funciona!!! É que estou a enviar no hash uma string do género: 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Ý Pois é grande, será limitação? Edited November 15, 2022 at 04:58 PM by samuquinha alterar base64 do pdf
Nel Posted November 15, 2022 at 05:12 PM Report #628182 Posted November 15, 2022 at 05:12 PM Em 15/11/2022 às 16:44, samuquinha disse: Sim, estou a enviar os parametros necessários Se alterar o parametro hashes do pedido para uma cena trivial (conforme exemplo do SAFE - Signature Service) {"numSignatures": 1, "hashes": ["MDEwDQYJYIZIAWUDBAIBBQAEIAOxESPLqLyNN4XvBW718h4QGtEyMKfQmLNcl6CFRKUB"], "clientData": { "processId": "c8976890-8772-4e4d-93d3-fe7d399afb29", "documentNames": ["documen_Name1"], "clientName": "clientTest" }, "credentialID": "xxxxxxpppppp" } já funciona!!! É que estou a enviar no hash uma string do género: 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Ý Pois é grande, será limitação? Parece grande! Estas a fazer o base64 encode?
samuquinha Posted November 15, 2022 at 05:39 PM Report #628183 Posted November 15, 2022 at 05:39 PM (edited) Em 15/11/2022 às 17:12, Nel disse: Parece grande! Estas a fazer o base64 encode? Sim, a string está em base64, mas tenho que confirmar se a libraria (usada para assinar documentos com o serviço Sign'Stash da Multicert), usa o algoritmo SHA-256 Apercebi-me também que tenho que adicionar o prefixo do SHA256. Parece-me que é um valor sempre fixo e que é "NDg0OTQ4MTM2OTk2MTM0NzIxMTAxMzQyMTUwNDMy", estou certo? Edited November 15, 2022 at 06:03 PM by samuquinha
Nel Posted November 15, 2022 at 07:30 PM Report #628187 Posted November 15, 2022 at 07:30 PM Em 15/11/2022 às 17:39, samuquinha disse: Sim, a string está em base64, mas tenho que confirmar se a libraria (usada para assinar documentos com o serviço Sign'Stash da Multicert), usa o algoritmo SHA-256 Apercebi-me também que tenho que adicionar o prefixo do SHA256. Parece-me que é um valor sempre fixo e que é "NDg0OTQ4MTM2OTk2MTM0NzIxMTAxMzQyMTUwNDMy", estou certo? Sim tens. byte[] sha256SigPrefix = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte) 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; $prefix = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; //se PHP
Popular Post bioshock Posted November 16, 2022 at 02:29 AM Popular Post Report #628188 Posted November 16, 2022 at 02:29 AM (edited) On 11/15/2022 at 12:13 PM, Nel said: Consegues criar o PDF com a assinatura OK? Fica com o warning de "identity Unknown"? O meu esta a ficar com erro mesmo. Estou a adaptar o tcpdf. Qual o package que usas? O meu fica com warning Validity Unknown, tem haver com o LTV, parece que o serviço http://ocsp.cmd.teste.cartaodecidadao.pt/publico/ocsp não consegue ser resolvido, talvez em produção fique resolvido. Utilizo o serviço SetaPDF Signer e em parceria com eles foi possível desenvolverem um addon para o serviço SAFE, já disponível no Github: https://github.com/Setasign/SetaPDF-Signer-Addon-SAFE Conforme prometido, fica a minha solução: Alterem os valores dos campos para se ajustar à v/ solução Apliquem as validações / trigger de exceptions etc que acharem adequados Pode haver um ou outro pequeno bug, visto que fiz uma limpeza para colocar aqui no fórum <?php /** * FA = Fornecedor Atributos * CMD = Chave Móvel Digital * Sistema requerente = Software de Facturação * * https://github.com/amagovpt/doc-SAFE * https://github.com/amagovpt/doc-AUTENTICACAO * https://amagovpt.github.io/doc-SAFE/AMA%20-%20SAFE%20Guia%20de%20Fluxos%20Complementares.pdf */ class Safe { /** * Holds the FA OAuth Authorization URL * * @var String */ const FA_OAUTH_ASK_AUTHORIZATION_URL = 'https://preprod.autenticacao.gov.pt/OAuth/AskAuthorization'; /** * Holds the FA OAuth Authorized URL * * @var String */ const FA_OAUTH_AUTHORIZED_URL = 'https://preprod.autenticacao.gov.pt/OAuth/Authorized'; /** * Holds the FA API URL (to fetch attributes) * * @var String */ const FA_API_URL = 'https://preprod.autenticacao.gov.pt/OAuthResourceServer/Api/AttributeManager'; /** * Holds the default FA Attributes to fetch * * @var Array */ const ATTRIBUTES = [ 'http://interop.gov.pt/MDC/Cidadao/NIC', 'http://interop.gov.pt/MDC/Cidadao/NomeProprio', 'http://interop.gov.pt/MDC/Cidadao/NomeApelido', 'http://interop.gov.pt/MDC/Cidadao/DataValidade', 'http://interop.gov.pt/MDC/Cidadao/DataNascimento', ]; /** * Holds the SAFE Authentication (which will be translated into Base64) * * @var String */ const SAFE_BASIC_AUTHENTICATION = 'clientTest:Test'; /** * Holds the SAFE Client Name * * @var String */ const SAFE_CLIENT_NAME = 'clientTest'; /** * Holds the SAFE API URL * * @var String */ const SAFE_API_URL = 'https://pprsafe.autenticacao.gov.pt/'; /** * Holds the SAFE Client ID * * @var String */ const SAFE_CLIENT_ID = '............'; } <?php class Auth extends Safe { /** * Returns the Authorization URL * https://amagovpt.github.io/doc-SAFE/AMA%20-%20SAFE%20Documento%20de%20integra%C3%A7%C3%A3o.pdf * * 1. Cidadão pede adesão ao serviço de assinatura de faturas, introduzindo os seguintes dados: * 2. Software de Faturação invoca FA para o cidadão se poder autenticar * 3. FA mostra a página de autenticação no mecanismo utilizado pelo Software de Faturação (e.g. WebView ou Browser); * 4. Cidadão efetua autenticação com CMD ou CC; * 5. Página da autenticação envia dados para o FA; * 6. FA valida a autenticação; * 7. FA pede criação de conta de assinatura, enviando para o SAFE os dados obtidos na autenticação; * * @return String */ public function getAuthorizationURL() { $attributes = $this->getURLAttributes(); $scopes = implode('%20', $attributes); // + $redirectURI = 'https://oVossoSite.com/safe-integration'; $redirectURI = urlencode($redirectURI); $url = sprintf ( '%s?redirect_uri=%s&client_id=%s&scope=%s&response_type=token', self::FA_OAUTH_ASK_AUTHORIZATION_URL, $redirectURI, self::SAFE_CLIENT_ID, $scopes, ); return $url; } /** * Fetches the attributes related with the access token provided. This function should be called 15/30s after redirection from AMA. * * @param String * * @return Array */ public function fetchAttributes($accessToken) { $postFields = ['token' => $accessToken]; $headers = ['Content-Type: application/json']; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::FA_API_URL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); $token = $response->token; // This is actually the "Process ID" $authenticationContextId = $response->authenticationContextId; return [$token, $authenticationContextId]; } /** * Checks the attributes values. Called right after fetching the attributes * * @param String * @param String * * @return Array */ public function checkAttributesValues($token, $authenticationContextId) { $url = self::FA_API_URL . "?token={$token}&authenticationContextId={$authenticationContextId}"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); // Grabs the content of interop [5] => createSignatureAccount?enterpriseNipc=.... $createSignatureAccount = json_decode($response[5]->value); return [$createSignatureAccount->accessToken, $createSignatureAccount->refreshToken]; } /** * Gets the SAFE Credential Id, which is a value that must be used everywhere through all the signing process. * * @param String * @param String * * @return String */ public function fetchSAFECredentialId($accessToken, $processId) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $accessToken, ]; $postFields = ['clientData' => ['processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME]]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'credentials/list'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); return $response->credentialIDs[0]; } /** * Gets the SAFE Certificate for the account, which is a value used when signing documents * * @param String * @param String * @param String * * @return Array */ public function fetchSAFECertificate($accessToken, $processId, $credentialId) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $accessToken, ]; $postFields = [ 'credentialID' => $credentialId, 'clientData' => ['processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME], 'certificates' => 'chain', ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'credentials/info'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $response; } /** * Generates a new access token * * @param String * @param String * @param String * * @return Array */ public function generateToken($refreshToken, $processId, $credentialId) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $refreshToken, ]; $postFields = [ 'credentialID' => $credentialId, 'clientData' => ['processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME], ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'signatureAccount/updateToken'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); return [$response->newAccessToken, $response->newRefreshToken]; } /** * Cancels the existing account * * @param String * @param String * @param String */ public function cancelAccount($accessToken, $processId, $credentialId) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $accessToken, ]; $postFields = [ 'credentialID' => $credentialId, 'clientData' => ['processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME], ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'signatureAccount/cancel'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_exec($ch); curl_close($ch); } /** * Gets the attributes to add to URL call * * @return String */ private function getURLAttributes() { $attributes = self::ATTRIBUTES; $signatureAttribute = $this->getSignatureAttribute(); array_push($attributes, $signatureAttribute); return $attributes; } /** * Gets the signature attribute to be added in the URL * * @return String */ private function getSignatureAttribute() { $vatNumber = 'contribuinte_do_cliente'; $additionalInfo = 'contribuinte_do_cliente' . time(); $email = ''; $expirationDate = date('Y-m-d', strtotime('+45 days')); $signaturesLimit = 450000; $creationName = self::SAFE_CLIENT_NAME; // Must be created on-the-fly $attribute = sprintf ( 'http://interop.gov.pt/SAFE/createSignatureAccount?enterpriseNipc=%s$enterpriseAdditionalInfo=%s$email=%s$signaturesLimit=%s$creationClientName=%s', $vatNumber, $additionalInfo, $email, $signaturesLimit, $creationName ); return $attribute; } } <?php require_once('vendor/SetaPDF/Autoload.php'); // Caso o Autoload não seja executado / tenham problemas, podem carregar os ficheiros manualmente use \SetaPDF_Signer_Signature_Module_ModuleInterface; use \SetaPDF_Signer_Signature_DictionaryInterface; use \SetaPDF_Signer_Signature_DocumentInterface; use \SetaPDF_Core_Reader_FilePath; use \SetaPDF_Core_Writer_File; use \SetaPDF_Core_Document; use \SetaPDF_Signer; use \SetaPDF_Signer_Asn1_Element; use \SetaPDF_Signer_Asn1_Oid; use \SetaPDF_Signer_Digest; class Sign extends Safe { /** * Requests certain file to be signed * * @param String|Boolean */ public function document($fileUrl) { try { $fileUrlSigned = 'output.pdf'; /** * Atribuir a esta variável, o valor da função fetchSAFECertificate(). Por norma este valor deve estar guardado na BD, pelo * que a variável devia de ficar algo como: * $certs = json_decode($campo_na_bd)->cert->certificates; */ $certs = []; $writer = new SetaPDF_Core_Writer_File($fileUrlSigned); $tmpWriter = new SetaPDF_Core_Writer_TempFile(); $document = SetaPDF_Core_Document::loadByFilename($fileUrl, $tmpWriter); // create a collection of trusted certificats: $trustedCertificates = new SetaPDF_Signer_X509_Collection($certs[count($certs) - 1]); $signer = new SetaPDF_Signer($document); $signer->setAllowSignatureContentLengthChange(false); $signer->setSignatureContentLength(16000); $module = new SetaPDFSignatureModule($fileUrl); $module->setCertificate($certs[0]); $module->setExtraCertificates($certs); // add a signature field manually to get access to its name $signatureField = $signer->addSignatureField(); // this is needed to add validation related information later $signer->setSignatureFieldName($signatureField->getQualifiedName()); $signer->sign($module); // create a new instance $document = SetaPDF_Core_Document::loadByFilename($tmpWriter->getPath(), $writer); // create a VRI collector instance $collector = new SetaPDF_Signer_ValidationRelatedInfo_Collector($trustedCertificates); // get VRI for the timestamp signature $vriData = $collector->getByFieldName( $document, $signatureField->getQualifiedName() ); // Tries to apply the LTV $dss = new SetaPDF_Signer_DocumentSecurityStore($document); $dss->addValidationRelatedInfoByFieldName( $signatureField->getQualifiedName(), $vriData->getCrls(), $vriData->getOcspResponses(), $vriData->getCertificates() ); // save and finish the final document $document->save()->finish(); return $fileUrlSigned; } catch (\Exception $e) { // Log error.. return false; } } /** * Authorize the access to the credential for remote signing by Queue * * @param String PDF Hash * * @return String Signature Activation Data (SAD) */ public function authorize($hash) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $accessToken, ]; $name = 'FR ABC/77'; $postFields = [ 'numSignatures' => 1, 'hashes' => [base64_encode($hash)], 'clientData' => [ 'processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME, 'documentNames' => [$name], ], 'credentialID' => $credentialId, ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'credentials/authorize'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); return $response->sad; } /** * Signature Hash Service by Queue * * @param String Signature Activation Data * @param String PDF Hash * * @return String */ public function signHash($sad, $hash) { $headers = [ 'Content-Type: application/json', 'Authorization: Basic ' . base64_encode(self::SAFE_BASIC_AUTHENTICATION), 'SAFEAuthorization: Bearer ' . $accessToken, ]; $postFields = [ 'sad' => $sad, 'hashes' => [base64_encode($hash)], 'signAlgo' => json_decode('campo_na_bd')->key->algo, // Igual ao comentário da variável $certs 'clientData' => [ 'processId' => $processId, 'clientName' => self::SAFE_CLIENT_NAME, ], 'credentialID' => $credentialId, ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::SAFE_API_URL . 'signatures/signHash'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $response = json_decode($response); return $response->signatures[0]; // Always the first result since we only sign a document } } class SetaPDFSignatureModule implements SetaPDF_Signer_Signature_Module_ModuleInterface, SetaPDF_Signer_Signature_DictionaryInterface, SetaPDF_Signer_Signature_DocumentInterface { use \SetaPDF_Signer_Signature_Module_PadesProxyTrait; /** * Holds the hash generated * * @var String */ private $hashGenerated; /** * Create a signature for the file in the given $tmpPath. * * @param SetaPDF_Core_Reader_FilePath $tmpPath * * @return string */ public function createSignature(SetaPDF_Core_Reader_FilePath $tmpPath) { $hashAlgorithm = 'sha256'; $padesModule = $this->_getPadesModule(); $padesModule->setDigest($hashAlgorithm); $hashValue = hash($hashAlgorithm, $padesModule->getDataToSign($tmpPath), true); $digestInfo = new SetaPDF_Signer_Asn1_Element( SetaPDF_Signer_Asn1_Element::SEQUENCE | SetaPDF_Signer_Asn1_Element::IS_CONSTRUCTED, '', [ new SetaPDF_Signer_Asn1_Element( SetaPDF_Signer_Asn1_Element::SEQUENCE | SetaPDF_Signer_Asn1_Element::IS_CONSTRUCTED, '', [ new SetaPDF_Signer_Asn1_Element( SetaPDF_Signer_Asn1_Element::OBJECT_IDENTIFIER, SetaPDF_Signer_Asn1_Oid::encode( SetaPDF_Signer_Digest::getOid($padesModule->getDigest()) ) ), new SetaPDF_Signer_Asn1_Element(SetaPDF_Signer_Asn1_Element::NULL) ] ), new SetaPDF_Signer_Asn1_Element( SetaPDF_Signer_Asn1_Element::OCTET_STRING, $hashValue ) ] ); // Calls the Sign class once again, since it holds the SAFE functions to authorize & sign document $sign = new Sign(); $sad = $sign->authorize((string)$digestInfo); $signatureValue = $sign->signHash($sad, (string)$digestInfo); // pass the signature value to the CMS structure $padesModule->setSignatureValue(base64_decode($signatureValue)); $this->hashGenerated = (string)$digestInfo; return $padesModule->getCms(); } /** * Returns the hash generated * * @return String */ public function getHashGenerated() { return $this->hashGenerated; } } Edited November 16, 2022 at 02:31 AM by bioshock 3 Report
bugmen Posted November 16, 2022 at 12:10 PM Report #628191 Posted November 16, 2022 at 12:10 PM Em 15/11/2022 às 12:13, Nel disse: Consegues criar o PDF com a assinatura OK? Fica com o warning de "identity Unknown"? O meu esta a ficar com erro mesmo. Estou a adaptar o tcpdf. Qual o package que usas? Eu também estou a desenvolver em PHP. @Nel conseguiste adaptar o tcpdf? Podes dar-me umas luzes sff ? Andei à procura de novas versões do tcpdf mas sem sucesso.
laboss Posted November 16, 2022 at 12:27 PM Report #628192 Posted November 16, 2022 at 12:27 PM Podem testar os pdf's aqui https://validador.autenticacao.gov.pt/validation Os meus ficam assim 1 Report
Nuno Bagulho Marques Posted November 16, 2022 at 12:40 PM Report #628194 Posted November 16, 2022 at 12:40 PM Bom dia! Estou a pegar no dossier Faturas eletrónicas e estou um bocado perdido no fluxo da informação. Imaginei que este assunto fosse semelhante à interação com a AT, mas parece-me mais complexo. Gostaria que alguém, por favor e resumidamente, me fizesse uma sinopse dos passos a dar, sendo que já construi o XML do documento, de acordo com a documentação da ESPAP. As dúvidas são: Devo assinar o meu documento PDF e incluído assinado no XML? Uma vez pronto o XML, a quem envio o documento para chegar ao destinatário do documento elketrónico? Quem utiliza o meu software, que passos deve dar? Obrigado
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now