Criação de um mini PHP SDK para solicitações de assinatura para Oracle Cloud Infrastructure API

A ideia de escrever esta biblioteca surgiu quando eu queria aproveitar ao máximo a  oferta gratuita do  Oracle Cloud Infrastructure, ou seja, 10 GB de armazenamento de objetos e 10 TB de tráfego de saída por mês. A diferença com o AWS S3 é  enorme . Infelizmente, o Oracle Cloud  não tem  um SDK disponível para a linguagem de programação ainda mais popular para desenvolvimento de sites. A boa notícia é que o serviço é  parcialmente compatível  com Amazon S3, o que significa que você pode usar ferramentas de desenvolvedor existentes e bem documentadas  , inclusive para PHP.





Para aqueles que estão ansiosos para ver o código, bem-vindo a  https://github.com/hitrov/oci-api-php-request-sign .





De fato, com as ferramentas disponíveis, você pode realizar quase todas as operações imagináveis ​​- criar, ler e excluir buckets e objetos (arquivos). As lixeiras podem ser públicas (com ou sem arquivos de listagem) e privadas. É possível fazer upload de arquivos para uma cesta privada, tendo apenas uma URL "secreta" (gerada manualmente usando o  CLI  ou a interface web - console Oracle Cloud). Na verdade, isso já pode ser suficiente para muitos cenários, especialmente se você gerar nomes de arquivos de força bruta no caso de não querer expô-los ao público.





Eu estava interessado na capacidade de "compartilhar" arquivos, isto é, compartilhar links públicos para arquivos e, é claro, restringir o acesso, se necessário. Com um pequeno número de arquivos, você pode fazer isso manualmente, mas estamos reunidos aqui para ter acesso programático. O AWS S3 chama isso de URL pré-assinado , enquanto a Oracle o  chama de solicitação  pré-autenticada .





Instalando AWS PHP SDK





composer require aws/aws-sdk-php
      
      



Abaixo, será mostrado onde obter acesso ( AWS_ACCESS_KEY_ID



e AWS_SECRET_ACCESS_KEY



.





O namespace pode ser visto





require('vendor/autoload.php');

$namespaceName = 'frpegp***';
$bucketName = 'test******05';
$region = 'eu-frankfurt-1';
$endpoint = "https://$namespaceName.compat.objectstorage.$region.oraclecloud.com";

$s3 = new Aws\S3\S3Client([
    'version' => 'latest',
    'region'  => $region,
    'endpoint' => $endpoint,
    'signature_version' => 'v4',
    'use_path_style_endpoint' => true,
    'credentials' => [
        'key'    => 'AKI***YYJ', // remove if you have env var AWS_ACCESS_KEY_ID
        'secret' => 'ndK***cIf', // remove if you have env var AWS_SECRET_ACCESS_KEY
    ],
]);

$cmd = $s3->getCommand('GetObject', [
    'Bucket' => $bucketName,
    'Key' => 'fff.txt'
]);

$request = $s3->createPresignedRequest($cmd, '+20 minutes');
var_dump($request);
      
      



object(GuzzleHttp\Psr7\Request)#146 (7) {
  ["method":"GuzzleHttp\Psr7\Request":private]=>
  string(3) "GET"
  ["uri":"GuzzleHttp\Psr7\Request":private]=>
  object(GuzzleHttp\Psr7\Uri)#148 (7) {
    ["scheme":"GuzzleHttp\Psr7\Uri":private]=>
    string(5) "https"
    ...
    ["host":"GuzzleHttp\Psr7\Uri":private]=>
    string(64) "{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com"
    ...
    ["path":"GuzzleHttp\Psr7\Uri":private]=>
    string(21) "/{bucket}/fff.txt"
    ["query":"GuzzleHttp\Psr7\Uri":private]=>
    string(329) "X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=&&&%2F20210211%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210211T093350Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=1e1b1***6ac992"
    ...
  }
}
      
      



Esta operação retorna uma solicitação PSR-7 em resposta  , a partir da qual você pode gerar um URL do formulário





https://{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/{bucket}/fff.txt?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***%2F20210210%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210210T185244Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=a167a***9a857







Mas, infelizmente, isso não permite revogar o acesso, por exemplo, se o link for "long-play".





,  API,  , .





, \\  ,  DNS   Email. API Reference and Endpoints.





, , , , - () Oracle Cloud  User Settings





Ações do perfil Oracle Cloud
Oracle Cloud

API Keys — Add API Key





Chaves API - Adicionar chave API
API Keys - Add API Key

Download private key ( ),  Add





Baixe a chave privada e adicione
Download Private Key and Add

,





Exemplo de arquivo de configuração
Configuration File example

, AWS PHP SDK, Customer Secret Keys ( AWS_ACCESS_KEY_ID



AWS_SECRET_ACCESS_KEY



Amazon.





Oracle Cloud Infrastructure mini PHP SDK ( !)





composer require hitrov/oci-api-php-request-sign
      
      



 PSR-4 .





require 'vendor/autoload.php';
use Hitrov\OCI\Signer;
      
      



( , , ).





OCI_TENANCY_ID=ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq
OCI_USER_ID=ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq
OCI_KEY_FINGERPRINT=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34
OCI_PRIVATE_KEY_FILENAME=/path/to/privatekey.pem
      
      



.





$signer = new Signer;
      
      



 https://github.com/hitrov/oci-api-php-request-sign#alternatives-for-providing-credentials , .





   CreatePreauthenticatedRequest.





( )





public function getHeaders(
    string $url, string $method = 'GET', ?string $body = null, ?string $contentType = 'application/json', string $dateString = null
): array
      
      







$curl = curl_init();
$url = 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/{namespaceName}/b/{bucketName}/p/';
$method = 'POST';
$body = '{"accessType": "ObjectRead", "name": "read-access-to-image.png", "objectName": "path/to/image.png", "timeExpires": "2021-03-01T00:00:00-00:00"}';

$headers = $signer->getHeaders($url, $method, $body, 'application/json');
var_dump($headers);

$curlOptions = [
  CURLOPT_URL => $url,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 5,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => $method,
  CURLOPT_HTTPHEADER => $headers,
];

if ($body) {
  // not needed for GET or HEAD requests
  $curlOptions[CURLOPT_POSTFIELDS] = $body;
}

curl_setopt_array($curl, $curlOptions);
$response = curl_exec($curl);
echo $response;
curl_close($curl);
      
      



array(6) {
  [0]=>
  string(35) "date: Mon, 08 Feb 2021 20:49:22 GMT"
  [1]=>
  string(50) "host: objectstorage.eu-frankfurt-1.oraclecloud.com"
  [2]=>
  string(18) "content-length: 76"
  [3]=>
  string(30) "content-type: application/json"
  [4]=>
  string(62) "x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="
  [5]=>
  string(538) "Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\""
}
      
      



{
  "accessUri": "/p/AlIlOEsMok7oE7YkN30KJUDjDKQjk493BKbuM-ANUNGdBBAHzHT_5lFlzYC9CQiA/n/{namespaceName}/b/{bucketName}/o/path/to/image.png",
  "id": "oHJQWGxpD+2PhDqtoewvLCf8/lYNlaIpbZHYx+mBryAad/q0LnFy37Me/quKhxEi:path/to/image.png",
  "name": "read-access-to-image.png",
  "accessType": "ObjectRead",
  "objectName": "path/to/image.png",
  "timeCreated": "2021-02-09T11:52:45.053Z",
  "timeExpires": "2021-03-01T00:00:00Z"
}
      
      



!





, . , – .





1) , « » (SIGNING_HEADERS_NAMES).  





  •  date





  • · (request-target)





  • · host





 POST|PUT|PATCH 





  • · content-length





  • · content-type





  • · x-content-sha256





$signingHeadersNames = $signer->getSigningHeadersNames('POST');
      
      



2) SHA256 «» –  base64





$bodyHashBase64 = $signer->getBodyHashBase64($body);
      
      



3) ,





date: Mon, 08 Feb 2021 20:51:33 GMT
(request-target): post /n/{namespaceName}/b/{bucketName}/p/
host: objectstorage.eu-frankfurt-1.oraclecloud.com
content-length: 76
content-type: application/json
x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
      
      



$signingString = $signer->getSigningString($url, $method, $body, 'application/json');
      
      



(2). , , 5 .





4) (3)  RSA-SHA256





$signature = $signer->calculateSignature($signingString, $privateKeyString);
      
      



5) KEY_ID , API Key, ,





"{OCITENANCYID}/{OCIUSERID}/{OCIKEY_FINGERPRINT}"







$keyId = $signer->getKeyId();
      
      



6)  ( 1



 Oracle)





Authorization: Signature version=\"1\",keyId=\"{KEY_ID}\",algorithm=\"rsa-sha256\",headers=\"{SIGNING_HEADERS_NAMES_STRING}\",signature=\"{SIGNATURE}\"







 SIGNING_HEADERS_NAMES_STRING – (1), .





date (request-target) host content-length content-type x-content-sha256







$signingHeadersNamesString = implode(' ', $signingHeadersNames);
$authorizationHeader = $signer->getAuthorizationHeader($keyId, $signingHeadersNamesString, $signature);
      
      







Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\"
      
      



- .  var_dump()



- (3),  (request-target)  . , , (6).





Recebi ajuda do artigo sobre a chamada REST do  Oracle Cloud Infrastructure (OCI) com curl . Alguns dos nomes de métodos são emprestados do SDK GoLang oficial  . Casos de teste -  do mesmo lugar .








All Articles