Azure / azure-sdk-for-php

Microsoft Azure SDK for PHP
http://azure.microsoft.com/en-us/develop/php/
Apache License 2.0
415 stars 273 forks source link

Support for SharedAccessSignature for Service Bus #992

Open steinmr opened 6 years ago

steinmr commented 6 years ago

I have the need for connecting to Azure Service Bus using a SharedAccessSignature. As far as I can see, this is not possible with the current library. I have written a proof of concept, but PHP is not my primary language, and I am wondering if someone can help me create the proper code to merge with the library (if that would be interesting). The POC kind of hacks the current implementation, but it proves the point, and I do not think it would be too much work to merge it properly. Usage is pretty much the same as before, just replace ServicesBuilder with ServicesBuilderToken when doing ServicesBuilder::getInstance()->createServiceBusService($connectionString) In the client code I handle the 401 that happens when the SharedAccessSignature expires, but potentially it should renew the token before it expires.

use WindowsAzure\Common\ServicesBuilder;
use WindowsAzure\Common\ServiceException;

use WindowsAzure\Common\Internal\ServiceBusSettings;
use WindowsAzure\ServiceBus\Models\ReceiveMessageOptions;
use WindowsAzure\Common\Internal\Utilities;
use WindowsAzure\Common\Internal\Resources;
use WindowsAzure\ServiceBus\ServiceBusRestProxy;

class ServiceBusTokenSettings extends ServiceBusSettings 
{
  public $sharedAccessSignature; 

  public function __construct(
    $serviceBusEndpoint,
    $filter,
    $sharedAccessSignature
  ) 
  {
    parent::__construct($serviceBusEndpoint, $filter);
    $this->sharedAccessSignature = $sharedAccessSignature;
  }

  public static function createFromConnectionString($connectionString) {
    // Todo: Move to Resources constants
    self::$validSettingKeys[] = "SharedAccessSignature";
    self::$validSettingKeys[] = "EntityPath";

    $tokenizedSettings = self::parseAndValidateKeys($connectionString);

    $sharedAccessSignature = $tokenizedSettings["SharedAccessSignature"];

    $endpoint = Utilities::tryGetValueInsensitive(
      Resources::SERVICE_BUS_ENDPOINT_NAME,
      $tokenizedSettings
    );

    return new self($endpoint, null, $sharedAccessSignature);

    // Todo: Add methods for creating these settings for SharedAccessSignature
    /*if (array_key_exists(Resources::SHARED_SHARED_ACCESS_KEY_NAME, $tokenizedSettings)) {
        return self::createServiceBusWithSasAuthentication($tokenizedSettings, $connectionString);
    }
    return self::createServiceBusWithWrapAuthentication($tokenizedSettings, $connectionString);*/
  }
}
class ServicesBuilderToken extends ServicesBuilder
{
  private static $_instance = null;

  public static function getInstance()
  {
      if (!isset(self::$_instance)) {
          self::$_instance = new self();
      }
      return self::$_instance;
  }

function createServiceBusService($connectionString)
{
    $settings = ServiceBusTokenSettings::createFromConnectionString(
        $connectionString
    );
    $httpClient = $this->httpClient();
    if(!is_null($settings->sharedAccessSignature))
    {
      $httpClient->setHeader("Authorization", $settings->sharedAccessSignature);
    }
    $serializer = $this->serializer();
    $serviceBusWrapper = new ServiceBusRestProxy(
        $httpClient,
        $settings->getServiceBusEndpointUri(),
        $serializer
    );
    // Todo: Create a SASToken-filter
    /*
    // Adding headers filter
    $headers = [];
    $headersFilter = new HeadersFilter($headers);
    $serviceBusWrapper = $serviceBusWrapper->withFilter($headersFilter);
    $filter = $settings->getFilter();
    return $serviceBusWrapper->withFilter($filter);
    */
    return $serviceBusWrapper;
  }
}