SignatureProvider.php 5.2 KB

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