SignatureProvider.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. /**
  42. * Resolves and signature provider and ensures a non-null return value.
  43. *
  44. * @param callable $provider Provider function to invoke.
  45. * @param string $version Signature version.
  46. * @param string $service Service name.
  47. * @param string $region Region name.
  48. *
  49. * @return SignatureInterface
  50. * @throws UnresolvedSignatureException
  51. */
  52. public static function resolve(callable $provider, $version, $service, $region)
  53. {
  54. $result = $provider($version, $service, $region);
  55. if ($result instanceof SignatureInterface) {
  56. return $result;
  57. }
  58. throw new UnresolvedSignatureException(
  59. "Unable to resolve a signature for $version/$service/$region.\n"
  60. . "Valid signature versions include v4 and anonymous."
  61. );
  62. }
  63. /**
  64. * Default SDK signature provider.
  65. *
  66. * @return callable
  67. */
  68. public static function defaultProvider()
  69. {
  70. return self::memoize(self::version());
  71. }
  72. /**
  73. * Creates a signature provider that caches previously created signature
  74. * objects. The computed cache key is the concatenation of the version,
  75. * service, and region.
  76. *
  77. * @param callable $provider Signature provider to wrap.
  78. *
  79. * @return callable
  80. */
  81. public static function memoize(callable $provider)
  82. {
  83. $cache = [];
  84. return function ($version, $service, $region) use (&$cache, $provider) {
  85. $key = "($version)($service)($region)";
  86. if (!isset($cache[$key])) {
  87. $cache[$key] = $provider($version, $service, $region);
  88. }
  89. return $cache[$key];
  90. };
  91. }
  92. /**
  93. * Creates signature objects from known signature versions.
  94. *
  95. * This provider currently recognizes the following signature versions:
  96. *
  97. * - v4: Signature version 4.
  98. * - anonymous: Does not sign requests.
  99. *
  100. * @return callable
  101. */
  102. public static function version()
  103. {
  104. return function ($version, $service, $region) {
  105. switch ($version) {
  106. case 's3v4':
  107. case 'v4':
  108. return $service === 's3'
  109. ? new S3SignatureV4($service, $region)
  110. : new SignatureV4($service, $region);
  111. case 'v4-unsigned-body':
  112. return new SignatureV4($service, $region, ['unsigned-body' => 'true']);
  113. case 'anonymous':
  114. return new AnonymousSignature();
  115. default:
  116. return null;
  117. }
  118. };
  119. }
  120. }