summaryrefslogtreecommitdiff
path: root/vendor/aws/aws-sdk-php/src/Signature/SignatureProvider.php
blob: c373208ebd7aec858cb2922f10c7f8c807551222 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
namespace Aws\Signature;

use Aws\Exception\UnresolvedSignatureException;
use Aws\Token\BearerTokenAuthorization;

/**
 * Signature providers.
 *
 * A signature provider is a function that accepts a version, service, and
 * region and returns a {@see SignatureInterface} object on success or NULL if
 * no signature can be created from the provided arguments.
 *
 * You can wrap your calls to a signature provider with the
 * {@see SignatureProvider::resolve} function to ensure that a signature object
 * is created. If a signature object is not created, then the resolve()
 * function will throw a {@see Aws\Exception\UnresolvedSignatureException}.
 *
 *     use Aws\Signature\SignatureProvider;
 *     $provider = SignatureProvider::defaultProvider();
 *     // Returns a SignatureInterface or NULL.
 *     $signer = $provider('v4', 's3', 'us-west-2');
 *     // Returns a SignatureInterface or throws.
 *     $signer = SignatureProvider::resolve($provider, 'no', 's3', 'foo');
 *
 * You can compose multiple providers into a single provider using
 * {@see Aws\or_chain}. This function accepts providers as arguments and
 * returns a new function that will invoke each provider until a non-null value
 * is returned.
 *
 *     $a = SignatureProvider::defaultProvider();
 *     $b = function ($version, $service, $region) {
 *         if ($version === 'foo') {
 *             return new MyFooSignature();
 *         }
 *     };
 *     $c = \Aws\or_chain($a, $b);
 *     $signer = $c('v4', 'abc', '123');     // $a handles this.
 *     $signer = $c('foo', 'abc', '123');    // $b handles this.
 *     $nullValue = $c('???', 'abc', '123'); // Neither can handle this.
 */
class SignatureProvider
{
    private static $s3v4SignedServices = [
        's3' => true,
        's3control' => true,
        's3-object-lambda' => true,
    ];

    /**
     * Resolves and signature provider and ensures a non-null return value.
     *
     * @param callable $provider Provider function to invoke.
     * @param string   $version  Signature version.
     * @param string   $service  Service name.
     * @param string   $region   Region name.
     *
     * @return SignatureInterface
     * @throws UnresolvedSignatureException
     */
    public static function resolve(callable $provider, $version, $service, $region)
    {
        $result = $provider($version, $service, $region);
        if ($result instanceof SignatureInterface
            || $result instanceof BearerTokenAuthorization
        ) {
            return $result;
        }

        throw new UnresolvedSignatureException(
            "Unable to resolve a signature for $version/$service/$region.\n"
            . "Valid signature versions include v4 and anonymous."
        );
    }

    /**
     * Default SDK signature provider.
     *
     * @return callable
     */
    public static function defaultProvider()
    {
        return self::memoize(self::version());
    }

    /**
     * Creates a signature provider that caches previously created signature
     * objects. The computed cache key is the concatenation of the version,
     * service, and region.
     *
     * @param callable $provider Signature provider to wrap.
     *
     * @return callable
     */
    public static function memoize(callable $provider)
    {
        $cache = [];
        return function ($version, $service, $region) use (&$cache, $provider) {
            $key = "($version)($service)($region)";
            if (!isset($cache[$key])) {
                $cache[$key] = $provider($version, $service, $region);
            }
            return $cache[$key];
        };
    }

    /**
     * Creates signature objects from known signature versions.
     *
     * This provider currently recognizes the following signature versions:
     *
     * - v4: Signature version 4.
     * - anonymous: Does not sign requests.
     *
     * @return callable
     */
    public static function version()
    {
        return function ($version, $service, $region) {
            switch ($version) {
                case 's3v4':
                case 'v4':
                    return !empty(self::$s3v4SignedServices[$service])
                        ? new S3SignatureV4($service, $region)
                        : new SignatureV4($service, $region);
                case 'v4a':
                    return !empty(self::$s3v4SignedServices[$service])
                        ? new S3SignatureV4($service, $region, ['use_v4a' => true])
                        : new SignatureV4($service, $region, ['use_v4a' => true]);
                case 'v4-unsigned-body':
                    return !empty(self::$s3v4SignedServices[$service])
                    ? new S3SignatureV4($service, $region, ['unsigned-body' => 'true'])
                    : new SignatureV4($service, $region, ['unsigned-body' => 'true']);
                case 'bearer':
                    return new BearerTokenAuthorization();
                case 'anonymous':
                    return new AnonymousSignature();
                default:
                    return null;
            }
        };
    }
}