SignatureProvider.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. namespace Aws\Signature;
  3. use Aws\Exception\UnresolvedSignatureException;
  4. /**
  5. * Signature providers.
  6. *
  7. * A signature provider is a function that accepts a version, service, and
  8. * region and returns a {@see SignatureInterface} object on success or NULL if
  9. * no signature can be created from the provided arguments.
  10. *
  11. * You can wrap your calls to a signature provider with the
  12. * {@see SignatureProvider::resolve} function to ensure that a signature object
  13. * is created. If a signature object is not created, then the resolve()
  14. * function will throw a {@see Aws\Exception\UnresolvedSignatureException}.
  15. *
  16. * use Aws\Signature\SignatureProvider;
  17. * $provider = SignatureProvider::defaultProvider();
  18. * // Returns a SignatureInterface or NULL.
  19. * $signer = $provider('v4', 's3', 'us-west-2');
  20. * // Returns a SignatureInterface or throws.
  21. * $signer = SignatureProvider::resolve($provider, 'no', 's3', 'foo');
  22. *
  23. * You can compose multiple providers into a single provider using
  24. * {@see Aws\or_chain}. This function accepts providers as arguments and
  25. * returns a new function that will invoke each provider until a non-null value
  26. * is returned.
  27. *
  28. * $a = SignatureProvider::defaultProvider();
  29. * $b = function ($version, $service, $region) {
  30. * if ($version === 'foo') {
  31. * return new MyFooSignature();
  32. * }
  33. * };
  34. * $c = \Aws\or_chain($a, $b);
  35. * $signer = $c('v4', 'abc', '123'); // $a handles this.
  36. * $signer = $c('foo', 'abc', '123'); // $b handles this.
  37. * $nullValue = $c('???', 'abc', '123'); // Neither can handle this.
  38. */
  39. class SignatureProvider
  40. {
  41. private static $s3v4SignedServices = [
  42. 's3' => true,
  43. 's3control' => true,
  44. ];
  45. /**
  46. * Resolves and signature provider and ensures a non-null return value.
  47. *
  48. * @param callable $provider Provider function to invoke.
  49. * @param string $version Signature version.
  50. * @param string $service Service name.
  51. * @param string $region Region name.
  52. *
  53. * @return SignatureInterface
  54. * @throws UnresolvedSignatureException
  55. */
  56. public static function resolve(callable $provider, $version, $service, $region)
  57. {
  58. $result = $provider($version, $service, $region);
  59. if ($result instanceof SignatureInterface) {
  60. return $result;
  61. }
  62. throw new UnresolvedSignatureException(
  63. "Unable to resolve a signature for $version/$service/$region.\n"
  64. . "Valid signature versions include v4 and anonymous."
  65. );
  66. }
  67. /**
  68. * Default SDK signature provider.
  69. *
  70. * @return callable
  71. */
  72. public static function defaultProvider()
  73. {
  74. return self::memoize(self::version());
  75. }
  76. /**
  77. * Creates a signature provider that caches previously created signature
  78. * objects. The computed cache key is the concatenation of the version,
  79. * service, and region.
  80. *
  81. * @param callable $provider Signature provider to wrap.
  82. *
  83. * @return callable
  84. */
  85. public static function memoize(callable $provider)
  86. {
  87. $cache = [];
  88. return function ($version, $service, $region) use (&$cache, $provider) {
  89. $key = "($version)($service)($region)";
  90. if (!isset($cache[$key])) {
  91. $cache[$key] = $provider($version, $service, $region);
  92. }
  93. return $cache[$key];
  94. };
  95. }
  96. /**
  97. * Creates signature objects from known signature versions.
  98. *
  99. * This provider currently recognizes the following signature versions:
  100. *
  101. * - v4: Signature version 4.
  102. * - anonymous: Does not sign requests.
  103. *
  104. * @return callable
  105. */
  106. public static function version()
  107. {
  108. return function ($version, $service, $region) {
  109. switch ($version) {
  110. case 's3v4':
  111. case 'v4':
  112. return !empty(self::$s3v4SignedServices[$service])
  113. ? new S3SignatureV4($service, $region)
  114. : new SignatureV4($service, $region);
  115. case 'v4-unsigned-body':
  116. return new SignatureV4($service, $region, ['unsigned-body' => 'true']);
  117. case 'anonymous':
  118. return new AnonymousSignature();
  119. default:
  120. return null;
  121. }
  122. };
  123. }
  124. }